Kaynağa Gözat

update code

Nick Peng 7 yıl önce
ebeveyn
işleme
72dd4e6cd3
11 değiştirilmiş dosya ile 1255 ekleme ve 162 silme
  1. 2 1
      Makefile
  2. 37 23
      dns_client.c
  3. 6 6
      dns_server.c
  4. 127 122
      fast_ping.c
  5. 5 3
      fast_ping.h
  6. 23 0
      include/atomic.h
  7. 20 7
      smartdns.c
  8. 908 0
      tlog.c
  9. 89 0
      tlog.h
  10. 34 0
      util.c
  11. 4 0
      util.h

+ 2 - 1
Makefile

@@ -1,8 +1,9 @@
 
 BIN=smartdns 
-OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o dns_server.o dns.o util.o
+OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o dns_server.o dns.o util.o tlog.o
 CFLAGS=-g -O0 -Wall 
 CFLAGS +=-Iinclude
+CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
 CXXFLAGS=-g -O0 -Wall -std=c++11 
 CXXFLAGS +=-Iinclude
 

+ 37 - 23
dns_client.c

@@ -23,6 +23,7 @@
 #include "hashtable.h"
 #include "list.h"
 #include "util.h"
+#include "tlog.h"
 #include <arpa/inet.h>
 #include <errno.h>
 #include <linux/filter.h>
@@ -73,6 +74,7 @@ struct dns_client {
 
 struct dns_server_info {
 	struct list_head list;
+	struct ping_host_struct *ping_host;
 	dns_server_type_t type;
 	unsigned short ss_family;
 	socklen_t addr_len;
@@ -85,6 +87,7 @@ struct dns_server_info {
 
 struct dns_query_struct {
 	atomic_t refcnt;
+	unsigned short sid;
 	struct list_head dns_request_list;
 	struct hlist_node domain_node;
 	char domain[DNS_MAX_CNAME_LEN];
@@ -96,6 +99,7 @@ struct dns_query_struct {
 };
 
 static struct dns_client client;
+static atomic_t dns_client_sid = ATOMIC_INIT(0);
 
 static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
 {
@@ -163,13 +167,14 @@ int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_typ
 		goto errout;
 	}
 	memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen);
-	pthread_mutex_lock(&client.server_list_lock);
-	list_add(&server_info->list, &client.dns_server_list);
-	pthread_mutex_unlock(&client.server_list_lock);
 
-	if (fast_ping_start(server_ip, 0, 60000, NULL, server_info) != 0) {
+	if (fast_ping_start(server_ip, 0, 60000, NULL, server_info) == NULL) {
 		goto errout;
 	}
+
+	pthread_mutex_lock(&client.server_list_lock);
+	list_add(&server_info->list, &client.dns_server_list);
+	pthread_mutex_unlock(&client.server_list_lock);
 	return 0;
 errout:
 	if (server_info) {
@@ -194,7 +199,7 @@ int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_
 		}
 		list_del(&server_info->list);
 		pthread_mutex_unlock(&client.server_list_lock);
-		if (fast_ping_stop(server_ip) != 0) {
+		if (fast_ping_stop(server_info->ping_host) != 0) {
 			printf("stop ping failed.\n");
 		}
 		free(server_info);
@@ -279,7 +284,10 @@ void _dns_client_query_release(struct dns_query_struct *query)
 	list_del(&query->dns_request_list);
 	hash_del(&query->domain_node);
 	pthread_mutex_unlock(&client.domain_map_lock);
+	tlog(TLOG_ERROR, "-------------%p, %d\n", query, atomic_read(&query->refcnt));
 	_dns_client_query_complete(query);
+	//TODO double free BUG://
+	memset(query, 0, sizeof(*query));
 	free(query);
 }
 
@@ -288,7 +296,7 @@ void _dns_client_query_get(struct dns_query_struct *query)
 	atomic_inc(&query->refcnt);
 }
 
-void dns_client_ping_result(const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr)
+void dns_client_ping_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr)
 {
 	struct dns_query_struct *query = userptr;
 
@@ -344,13 +352,16 @@ void _dns_client_period_run()
 	return;
 }
 
-static struct dns_query_struct *_dns_client_get_request(char *domain)
+static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char *domain)
 {
 	struct dns_query_struct *query = NULL;
 	struct hlist_node *tmp = NULL;
+	unsigned int key;
 
+	key = hash_string(domain);
+	key = jhash(&sid, sizeof(sid), key);
 	pthread_mutex_lock(&client.domain_map_lock);
-	hash_for_each_possible_safe(client.domain_map, query, tmp, domain_node, hash_string(domain))
+	hash_for_each_possible_safe(client.domain_map, query, tmp, domain_node, key)
 	{
 		if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) {
 			continue;
@@ -374,7 +385,7 @@ static int _dns_client_process_answer(char *domain, struct dns_packet *packet)
 	int ret = -1;
 	int A_num = 0;
 
-	query = _dns_client_get_request(domain);
+	query = _dns_client_get_request(packet->head.id, domain);
 	if (query == NULL) {
 		return -1;
 	}
@@ -389,7 +400,7 @@ static int _dns_client_process_answer(char *domain, struct dns_packet *packet)
 				printf("%s %d : %d.%d.%d.%d\n", name, ttl, addr[0], addr[1], addr[2], addr[3]);
 				sprintf(name, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
 				_dns_client_query_get(query);
-				if (fast_ping_start(name, 1, 900, dns_client_ping_result, query) != 0) {
+				if (fast_ping_start(name, 1, 700, dns_client_ping_result, query) == NULL) {
 					_dns_client_query_release(query);
 				}
 				A_num++;
@@ -400,7 +411,7 @@ static int _dns_client_process_answer(char *domain, struct dns_packet *packet)
 				sprintf(name, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
 						addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
 				_dns_client_query_get(query);
-				if (fast_ping_start(name, 1, 900, dns_client_ping_result, query) != 0) {
+				if (fast_ping_start(name, 1, 700, dns_client_ping_result, query) == NULL) {
 					_dns_client_query_release(query);
 				}
 			} break;
@@ -451,8 +462,8 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 		return -1;
 	}
 
-	printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount,
-		   packet->head.nrcount, inpacket_len);
+	printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount,
+		   packet->head.nrcount, inpacket_len, packet->head.id);
 
 	rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &rr_count);
 	for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
@@ -574,7 +585,7 @@ static int _dns_client_send_query(struct dns_query_struct *query, char *doamin)
 	head.qr = DNS_OP_QUERY;
 	head.rd = 0;
 	head.ra = 0;
-	head.id = 1;
+	head.id = query->sid;
 
 	dns_packet_init(packet, DNS_PACKSIZE, &head);
 	dns_add_domain(packet, doamin, DNS_T_A, DNS_C_IN);
@@ -591,6 +602,7 @@ int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr)
 {
 	struct dns_query_struct *query = NULL;
 	int ret = 0;
+	unsigned int key = 0;
 
 	query = malloc(sizeof(*query));
 	if (query == NULL) {
@@ -605,6 +617,7 @@ int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr)
 	query->callback = callback;
 	query->result.ttl_v4 = -1;
 	query->result.ttl_v6 = -1;
+	query->sid = atomic_inc_return(&dns_client_sid);
 
 	_dns_client_query_get(query);
 	ret = _dns_client_send_query(query, domain);
@@ -612,9 +625,11 @@ int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr)
 		goto errout_del_list;
 	}
 
+	key = hash_string(domain);
+	key = jhash(&query->sid, sizeof(query->sid), key);
 	pthread_mutex_lock(&client.domain_map_lock);
 	list_add_tail(&query->dns_request_list, &client.dns_request_list);
-	hash_add(client.domain_map, &query->domain_node, hash_string(domain));
+	hash_add(client.domain_map, &query->domain_node, key);
 	pthread_mutex_unlock(&client.domain_map_lock);
 
 	return 0;
@@ -730,14 +745,6 @@ int dns_client_init()
 		goto errout;
 	}
 
-	client.run = 1;
-	client.udp = fd;
-	ret = pthread_create(&client.tid, &attr, _dns_client_work, NULL);
-	if (ret != 0) {
-		fprintf(stderr, "create client work thread failed, %s\n", strerror(errno));
-		goto errout;
-	}
-
 	pthread_mutex_init(&client.server_list_lock, 0);
 	INIT_LIST_HEAD(&client.dns_server_list);
 
@@ -747,6 +754,13 @@ int dns_client_init()
 	INIT_LIST_HEAD(&client.dns_request_list);
 
 	client.epoll_fd = epollfd;
+	client.run = 1;
+	client.udp = fd;
+	ret = pthread_create(&client.tid, &attr, _dns_client_work, NULL);
+	if (ret != 0) {
+		fprintf(stderr, "create client work thread failed, %s\n", strerror(errno));
+		goto errout;
+	}
 
 	if (dns_client_start()) {
 		fprintf(stderr, "start client failed.\n");

+ 6 - 6
dns_server.c

@@ -20,6 +20,7 @@
 #include "dns.h"
 #include "util.h"
 #include "atomic.h"
+#include "tlog.h"
 #include "hashtable.h"
 #include "list.h"
 #include "dns_client.h"
@@ -157,13 +158,13 @@ static int _dns_add_rrs(struct dns_packet *packet, struct dns_request *request)
 			}
 		}
 
-		ret = dns_add_PTR(packet, DNS_RRS_AN, request->domain, 60 * 60, hostname);
+		ret = dns_add_PTR(packet, DNS_RRS_AN, request->domain, 30, hostname);
 	} break;
 	case DNS_T_A:
-		ret = dns_add_A(packet, DNS_RRS_AN, request->domain, 60 * 60, request->ipv4_addr);
+		ret = dns_add_A(packet, DNS_RRS_AN, request->domain, 30, request->ipv4_addr);
 		break;
 	case DNS_T_AAAA:
-		ret = dns_add_AAAA(packet, DNS_RRS_AN, request->domain, 60 * 60, request->ipv6_addr);
+		ret = dns_add_AAAA(packet, DNS_RRS_AN, request->domain, 30, request->ipv6_addr);
 		break;
 	default:
 		break;
@@ -224,7 +225,6 @@ static int dns_server_resolve_callback(char *domain, struct dns_result *result,
 		return -1;
 	}
 
-
 	memcpy(request->ipv4_addr, result->addr_ipv4, 4);
 	//memcpy(request->ipv6_addr, result->addr_ipv6, 16);
 	request->qtype = DNS_T_A;
@@ -241,7 +241,7 @@ static int dns_server_resolve_callback(char *domain, struct dns_result *result,
 
 	}
 
-	printf("free query server %p\n", request);
+	tlog(TLOG_ERROR, "free query server %p\n", request);
 	memset(request, 0, sizeof(*request));
 	free(request);
 
@@ -308,7 +308,7 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so
 		break;
 	}
 
-	printf("query server %p\n", request);
+	tlog(TLOG_ERROR, "query server %p\n", request);
 	atomic_set(&request->refcnt, 1);
 	dns_client_query(request->domain, dns_server_resolve_callback, request);
 

+ 127 - 122
fast_ping.c

@@ -19,6 +19,8 @@
 #include "fast_ping.h"
 #include "atomic.h"
 #include "hashtable.h"
+#include "tlog.h"
+#include "util.h"
 #include <arpa/inet.h>
 #include <errno.h>
 #include <linux/filter.h>
@@ -43,6 +45,8 @@
 
 struct fast_ping_packet_msg {
 	struct timeval tv;
+	unsigned int sid;
+	unsigned int seq;
 };
 
 struct fast_ping_packet {
@@ -57,7 +61,7 @@ struct ping_host_struct {
 	atomic_t ref;
 	struct hlist_node host_node;
 	struct hlist_node addr_node;
-	int type;
+	FAST_PING_TYPE type;
 
 	void *userptr;
 	fast_ping_result ping_callback;
@@ -70,7 +74,12 @@ struct ping_host_struct {
 	int timeout;
 	int count;
 	int send;
-	struct sockaddr addr;
+	unsigned int sid;
+	union {
+		struct sockaddr addr;
+		struct sockaddr_in6 in6;
+		struct sockaddr_in in;
+	};
 	socklen_t addr_len;
 	struct fast_ping_packet packet;
 };
@@ -93,6 +102,7 @@ struct fast_ping_struct {
 };
 
 static struct fast_ping_struct ping;
+static atomic_t ping_sid = ATOMIC_INIT(0);
 
 uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
 {
@@ -270,6 +280,8 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
 	icmp6->icmp6_seq = htons(ping_host->seq);
 
 	gettimeofday(&packet->msg.tv, 0);
+	packet->msg.sid = ping_host->sid;
+	packet->msg.seq = ping_host->seq;
 	icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
 
 	len = sendto(ping_host->fd, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
@@ -299,6 +311,8 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
 	icmp->icmp_seq = htons(ping_host->seq);
 
 	gettimeofday(&packet->msg.tv, 0);
+	packet->msg.sid = ping_host->sid;
+	packet->msg.seq = ping_host->seq;
 	icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
 
 	len = sendto(ping_host->fd, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
@@ -317,9 +331,9 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host)
 {
 	int ret = -1;
 
-	if (ping_host->type == AF_INET) {
+	if (ping_host->type == FAST_PING_ICMP) {
 		ret = _fast_ping_sendping_v4(ping_host);
-	} else if (ping_host->type == AF_INET6) {
+	} else if (ping_host->type == FAST_PING_ICMP6) {
 		ret = _fast_ping_sendping_v6(ping_host);
 	}
 
@@ -333,15 +347,15 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host)
 	return 0;
 }
 
-static int _fast_ping_create_sock(int protocol)
+static int _fast_ping_create_sock(FAST_PING_TYPE type)
 {
 	int fd = -1;
 	struct ping_host_struct *icmp_host = NULL;
 	struct epoll_event event;
 
-	switch (protocol) {
-	case IPPROTO_ICMP:
-		fd = socket(AF_INET, SOCK_RAW, protocol);
+	switch (type) {
+	case FAST_PING_ICMP:
+		fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 		if (fd < 0) {
 			fprintf(stderr, "create icmp socket failed.\n");
 			goto errout;
@@ -349,8 +363,8 @@ static int _fast_ping_create_sock(int protocol)
 		_fast_ping_install_filter_v4(fd);
 		icmp_host = &ping.icmp_host;
 		break;
-	case IPPROTO_ICMPV6:
-		fd = socket(AF_INET6, SOCK_RAW, protocol);
+	case FAST_PING_ICMP6:
+		fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
 		if (fd < 0) {
 			fprintf(stderr, "create icmp socket failed.\n");
 			goto errout;
@@ -358,6 +372,8 @@ static int _fast_ping_create_sock(int protocol)
 		_fast_ping_install_filter_v6(fd);
 		icmp_host = &ping.icmp6_host;
 		break;
+	default:
+		return -1;
 	}
 
 	event.events = EPOLLIN;
@@ -367,7 +383,7 @@ static int _fast_ping_create_sock(int protocol)
 	}
 
 	icmp_host->fd = fd;
-	icmp_host->type = AF_PACKET;
+	icmp_host->type = type;
 	return fd;
 
 errout:
@@ -375,17 +391,17 @@ errout:
 	return -1;
 }
 
-static int _fast_ping_create_icmp(int protocol)
+static int _fast_ping_create_icmp(FAST_PING_TYPE type)
 {
 	int fd = 0;
 	int *set_fd = NULL;
 
 	pthread_mutex_lock(&ping.lock);
-	switch (protocol) {
-	case IPPROTO_ICMP:
+	switch (type) {
+	case FAST_PING_ICMP:
 		set_fd = &ping.fd_icmp;
 		break;
-	case IPPROTO_ICMPV6:
+	case FAST_PING_ICMP6:
 		set_fd = &ping.fd_icmp6;
 		break;
 	default:
@@ -397,7 +413,7 @@ static int _fast_ping_create_icmp(int protocol)
 		goto out;
 	}
 
-	fd = _fast_ping_create_sock(protocol);
+	fd = _fast_ping_create_sock(type);
 	if (fd < 0) {
 		goto errout;
 	}
@@ -414,7 +430,8 @@ errout:
 	return -1;
 }
 
-void fast_ping_print_result(const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr)
+void fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno,
+							struct timeval *tv, void *userptr)
 {
 	if (result == PING_RESULT_RESPONSE) {
 		double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
@@ -424,7 +441,7 @@ void fast_ping_print_result(const char *host, FAST_PING_RESULT result, struct so
 	}
 }
 
-int fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr)
+struct ping_host_struct *fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr)
 {
 	struct ping_host_struct *ping_host = NULL;
 	struct addrinfo *gai = NULL;
@@ -433,25 +450,28 @@ int fast_ping_start(const char *host, int count, int timeout, fast_ping_result p
 	uint32_t hostkey;
 	uint32_t addrkey;
 	int fd = -1;
+	FAST_PING_TYPE type;
 
 	domain = _fast_ping_getdomain(host);
 	if (domain < 0) {
-		return -1;
+		return NULL;
 	}
 
 	switch (domain) {
 	case AF_INET:
 		icmp_proto = IPPROTO_ICMP;
+		type = FAST_PING_ICMP;
 		break;
 	case AF_INET6:
 		icmp_proto = IPPROTO_ICMPV6;
+		type = FAST_PING_ICMP6;
 		break;
 	default:
-		return -1;
+		return NULL;
 		break;
 	}
 
-	fd = _fast_ping_create_icmp(icmp_proto);
+	fd = _fast_ping_create_icmp(type);
 	if (fd < 0) {
 		goto errout;
 	}
@@ -469,24 +489,28 @@ int fast_ping_start(const char *host, int count, int timeout, fast_ping_result p
 	int interval = 1000;
 	memset(ping_host, 0, sizeof(*ping_host));
 	strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
-	ping_host->type = domain;
 	ping_host->fd = fd;
 	ping_host->timeout = timeout;
 	ping_host->count = count;
+	ping_host->type = type;
 	ping_host->userptr = userptr;
+	atomic_set(&ping_host->ref, 0);
+	ping_host->sid = atomic_inc_return(&ping_sid);
 	if (ping_callback) {
 		ping_host->ping_callback = ping_callback;
 	} else {
 		ping_host->ping_callback = fast_ping_print_result;
 	}
 	ping_host->interval = (timeout > interval) ? timeout : interval;
-	memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
 	ping_host->addr_len = gai->ai_addrlen;
-
-	atomic_set(&ping_host->ref, 0);
+	if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
+		goto errout;
+	}
+	memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
 
 	hostkey = hash_string(ping_host->host);
 	addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
+	addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
 	pthread_mutex_lock(&ping.map_lock);
 	_fast_ping_host_get(ping_host);
 	hash_add(ping.hostmap, &ping_host->host_node, hostkey);
@@ -496,7 +520,7 @@ int fast_ping_start(const char *host, int count, int timeout, fast_ping_result p
 	freeaddrinfo(gai);
 
 	_fast_ping_sendping(ping_host);
-	return 0;
+	return ping_host;
 errout:
 	if (fd > 0) {
 		close(fd);
@@ -510,26 +534,11 @@ errout:
 		free(ping_host);
 	}
 
-	return -1;
+	return NULL;
 }
 
-int fast_ping_stop(const char *host)
+int fast_ping_stop(struct ping_host_struct *ping_host)
 {
-	struct ping_host_struct *ping_host;
-	uint32_t key;
-	key = hash_string(host);
-	pthread_mutex_lock(&ping.map_lock);
-	hash_for_each_possible(ping.hostmap, ping_host, host_node, key)
-	{
-		if (strncmp(host, ping_host->host, PING_MAX_HOSTLEN) == 0) {
-			break;
-		}
-	}
-	if (ping_host == NULL) {
-		pthread_mutex_unlock(&ping.map_lock);
-		return -1;
-	}
-	pthread_mutex_unlock(&ping.map_lock);
 	_fast_ping_host_put(ping_host);
 	return 0;
 }
@@ -543,46 +552,38 @@ static void tv_sub(struct timeval *out, struct timeval *in)
 	out->tv_sec -= in->tv_sec;
 }
 
-static int _fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len, struct timeval *tvrecv)
+static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
 {
 	int icmp_len;
 	struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
 	struct icmp6_hdr *icmp6 = &packet->icmp6;
-	struct timeval tvresult = *tvrecv;
 
 	if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
-		return -1;
+		return NULL;
 	}
 
 	icmp_len = data_len;
 	if (icmp_len < 16) {
-		return -1;
+		return NULL;
 	}
 
 	if (icmp6->icmp6_id != ping.ident) {
-		return -1;
+		return NULL;
 	}
 
-	struct timeval *tvsend = &packet->msg.tv;
-	tv_sub(&tvresult, tvsend);
-
-	if (ping_host->ping_callback) {
-		ping_host->ping_callback(ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tvresult, ping_host->userptr);
-	}
-	return 0;
+	return packet;
 }
 
-static int _fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len, struct timeval *tvrecv)
+static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
 {
 	struct ip *ip = (struct ip *)packet_data;
 	struct fast_ping_packet *packet;
 	struct icmp *icmp;
-	struct timeval tvresult = *tvrecv;
 	int hlen;
 	int icmp_len;
 
 	if (ip->ip_p != IPPROTO_ICMP) {
-		return -1;
+		return NULL;
 	}
 
 	hlen = ip->ip_hl << 2;
@@ -591,84 +592,56 @@ static int _fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *pa
 	icmp_len = data_len - hlen;
 
 	if (icmp_len < 16) {
-		return -1;
+		return NULL;
 	}
 
 	if (icmp->icmp_type != ICMP_ECHOREPLY) {
-		return -1;
+		return NULL;
 	}
 
 	if (icmp->icmp_id != ping.ident) {
-		return -1;
-	}
-
-	struct timeval *tvsend = &packet->msg.tv;
-	tv_sub(&tvresult, tvsend);
-	if (ping_host->ping_callback) {
-		ping_host->ping_callback(ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tvresult, ping_host->userptr);
+		return NULL;
 	}
 
-	return 0;
+	return packet;
 }
 
-static int _fast_ping_recvping(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
+struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
 {
+	struct fast_ping_packet *packet = NULL;
 
-	if (ping_host->type == AF_INET6) {
-		if (_fast_ping_icmp6_packet(ping_host, inpacket, len, tvrecv)) {
+	if (ping_host->type == FAST_PING_ICMP6) {
+		packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
+		if (packet == NULL) {
 			goto errout;
 		}
-	} else if (ping_host->type == AF_INET) {
-		if (_fast_ping_icmp_packet(ping_host, inpacket, len, tvrecv)) {
+	} else if (ping_host->type == FAST_PING_ICMP) {
+		packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
+		if (packet == NULL) {
 			goto errout;
 		}
-	}
-
-	return 0;
-errout:
-	return -1;
-}
-
-#if 0
-static int _fast_ping_gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len)
-{
-	struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr;
-	host[0] = 0;
-	switch (addr_store->ss_family) {
-	case AF_INET: {
-		struct sockaddr_in *addr_in;
-		addr_in = (struct sockaddr_in *)addr;
-		inet_ntop(AF_INET, &addr_in->sin_addr, host, addr_len);
-	} break;
-	case AF_INET6: {
-		struct sockaddr_in6 *addr_in6;
-		addr_in6 = (struct sockaddr_in6 *)addr;
-		if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
-			struct sockaddr_in addr_in4;
-			memset(&addr_in4, 0, sizeof(addr_in4));
-			memcpy(&addr_in4.sin_addr.s_addr, addr_in6->sin6_addr.s6_addr + 12, sizeof(addr_in4.sin_addr.s_addr));
-		} else {
-			inet_ntop(AF_INET6, &addr_in6->sin6_addr, host, addr_len);
-		}
-	} break;
-	default:
+	} else {
 		goto errout;
-		break;
 	}
-	return 0;
+
+	return packet;
 errout:
-	return -1;
+	return NULL;
 }
-#endif
 
-static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now)
+static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct timeval *now)
 {
 	int len;
 	u_char inpacket[ICMP_INPACKET_SIZE];
 	struct sockaddr_storage from;
 	struct ping_host_struct *recv_ping_host;
+	struct fast_ping_packet *packet = NULL;
 	socklen_t from_len = sizeof(from);
 	uint32_t addrkey;
+	struct timeval tvresult = *now;
+	struct timeval *tvsend = NULL;
+	unsigned int sid;
+	unsigned int seq;
 
 	len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
 	if (len < 0) {
@@ -676,11 +649,21 @@ static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval
 		goto errout;
 	}
 
+	packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
+	if (packet == NULL) {
+		tlog(TLOG_ERROR, "recv ping packet failed.");
+		goto errout;
+	}
+
 	addrkey = jhash(&from, from_len, 0);
+	tvsend = &packet->msg.tv;
+	sid = packet->msg.sid;
+	seq = packet->msg.seq;
+	addrkey = jhash(&sid, sizeof(sid), addrkey);
 	pthread_mutex_lock(&ping.map_lock);
 	hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
 	{
-		if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0) {
+		if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
 			break;
 		}
 	}
@@ -690,13 +673,19 @@ static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval
 		return -1;
 	}
 
-	recv_ping_host->send = 0;
-
-	_fast_ping_recvping(recv_ping_host, inpacket, len, now);
+	if (recv_ping_host->seq != seq) {
+		tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
+		return -1;
+	}
 
-	if (recv_ping_host->count >= 0) {
-		recv_ping_host->count--;
+	tv_sub(&tvresult, tvsend);
+	if (recv_ping_host->ping_callback) {
+		recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
+									  recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
 	}
+
+	recv_ping_host->send = 0;
+
 	if (recv_ping_host->count == 0) {
 		_fast_ping_host_put(recv_ping_host);
 	}
@@ -705,6 +694,22 @@ errout:
 	return -1;
 }
 
+static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now)
+{
+	int ret = -1;
+
+	switch (ping_host->type) {
+	case FAST_PING_ICMP6:
+	case FAST_PING_ICMP:
+		ret = _fast_ping_process_icmp(ping_host, now);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
 static void _fast_ping_period_run()
 {
 	struct ping_host_struct *ping_host;
@@ -722,7 +727,8 @@ static void _fast_ping_period_run()
 		tv_sub(&interval, &ping_host->last);
 		millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
 		if (millisecond > ping_host->timeout && ping_host->send == 1) {
-			ping_host->ping_callback(ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval, ping_host->userptr);
+			ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
+									 ping_host->userptr);
 			ping_host->send = 0;
 		}
 
@@ -806,19 +812,18 @@ int fast_ping_init()
 		goto errout;
 	}
 
-	ping.run = 1;
-	ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
-	if (ret != 0) {
-		fprintf(stderr, "create ping work thread failed, %s\n", strerror(errno));
-		goto errout;
-	}
-
 	pthread_mutex_init(&ping.map_lock, 0);
 	pthread_mutex_init(&ping.lock, 0);
 	hash_init(ping.hostmap);
 	hash_init(ping.addrmap);
 	ping.epoll_fd = epollfd;
 	ping.ident = getpid();
+	ping.run = 1;
+	ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
+	if (ret != 0) {
+		fprintf(stderr, "create ping work thread failed, %s\n", strerror(errno));
+		goto errout;
+	}
 
 	return 0;
 errout:

+ 5 - 3
fast_ping.h

@@ -9,6 +9,7 @@ extern "C" {
 
 typedef enum {
 	FAST_PING_ICMP = 1,
+	FAST_PING_ICMP6 = 2,
 	FAST_PING_TCP,
 	FAST_PING_UDP
 } FAST_PING_TYPE;
@@ -18,11 +19,12 @@ typedef enum {
 	PING_RESULT_TIMEOUT = 2,
 } FAST_PING_RESULT;
 
-typedef void (*fast_ping_result)(const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr);
+struct ping_host_struct;
+typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr);
 
-int fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr);
+struct ping_host_struct *fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr);
 
-int fast_ping_stop(const char *host);
+int fast_ping_stop(struct ping_host_struct *ping_host);
 
 int fast_ping_init();
 

+ 23 - 0
include/atomic.h

@@ -91,6 +91,29 @@ static inline void atomic_dec( atomic_t *v )
 	(void)__sync_fetch_and_sub(&v->counter, 1);
 }
 
+/**
+ * Increment atomic variable
+ * @param v pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+static inline int atomic_inc_return( atomic_t *v )
+{
+	return __sync_fetch_and_add(&v->counter, 1);
+}
+
+/**
+ * @brief decrement atomic variable
+ * @param v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_dec_return( atomic_t *v )
+{
+	return __sync_fetch_and_sub(&v->counter, 1);
+}
+
 /**
  * @brief Decrement and test
  * @param v pointer of type atomic_t

+ 20 - 7
smartdns.c

@@ -25,12 +25,17 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-
 int smartdns_init()
 {
     int ret;
 
-    ret = fast_ping_init();
+	ret = tlog_init(".", "smartdns.log", 1024 * 1024, 8, 1, 0, 0);
+    if (ret != 0) {
+		fprintf(stderr, "start tlog failed.\n");
+		goto errout;
+	}
+
+	ret = fast_ping_init();
     if (ret != 0) {
         fprintf(stderr, "start ping failed.\n");
         goto errout;
@@ -48,9 +53,10 @@ int smartdns_init()
         goto errout;
     }
 
-	//dns_add_server("192.168.1.1", 53, DNS_SERVER_UDP);
+	dns_add_server("192.168.1.1", 53, DNS_SERVER_UDP);
     dns_add_server("114.114.114.114", 53, DNS_SERVER_UDP);
 	dns_add_server("123.207.137.88", 53, DNS_SERVER_UDP);
+	fast_ping_start("192.168.1.1", 10, 1000, 0, 0);
 	return 0;
 errout:
 
@@ -65,10 +71,9 @@ int smartdns_run()
 void smartdns_exit()
 {
     fast_ping_exit();
-
     dns_client_exit();
-
     dns_server_exit();
+	tlog_exit();
 }
 
 struct data {
@@ -193,13 +198,21 @@ int rbtree_test()
 }
 #endif
 
+#include <signal.h>
+
+void sig_handle(int sig)
+{
+	tlog(TLOG_ERROR, "process exit.\n");
+	sleep(1);
+	_exit(0);
+}
 int main(int argc, char *argv[])
 {
     int ret;
 
     atexit(smartdns_exit);
-
-    ret = smartdns_init();
+	signal(SIGABRT, sig_handle);
+	ret = smartdns_init();
     if (ret != 0) {
         fprintf(stderr, "init smartdns failed.\n");
         goto errout;

+ 908 - 0
tlog.c

@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2018 Ruilin Peng (Nick) <[email protected]>
+ */
+
+#include "tlog.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define TLOG_BUFF_SIZE (1024 * 128)
+#define TLOG_MAX_LINE_LEN (1024)
+#define TLOG_TMP_LEN 128
+#define TLOG_LOG_SIZE (1024 * 1024 * 50)
+#define TLOG_LOG_COUNT 32
+
+struct oldest_log {
+    char name[TLOG_TMP_LEN];
+    time_t mtime;
+};
+
+struct tlog {
+    char *buff;
+    int buffsize;
+    int start;
+    int end;
+    int ext_end;
+
+    int run;
+    pthread_t tid;
+    pthread_mutex_t lock;
+    pthread_cond_t cond;
+    pthread_cond_t client_cond;
+    int waiters;
+    int is_wait;
+
+    int fd;
+    int fd_lock;
+
+    off_t filesize;
+    char logdir[PATH_MAX];
+    char logname[PATH_MAX];
+    int logsize;
+    int logcount;
+    int block;
+    int dropped;
+    int zip_pid;
+    int multi_log;
+    int logscreen;
+};
+
+typedef int (*list_callback)(const char *name, struct dirent *entry, void *user);
+
+struct tlog tlog;
+static tlog_level tlog_set_level = TLOG_INFO;
+tlog_format_func tlog_format;
+static unsigned int tlog_localtime_lock = 0;
+
+static const char *tlog_level_str[] = {
+    "DEBUG",
+    "INFO",
+    "NOTICE",
+    "WARN",
+    "ERROR",
+    "FATAL",
+};
+
+static inline void _tlog_spin_lock(unsigned int *lock)
+{
+    while (1) {
+        int i;
+        for (i = 0; i < 10000; i++) {
+            if (__sync_bool_compare_and_swap(lock, 0, 1)) {
+                return;
+            }
+        }
+        sched_yield();
+    }
+}
+
+static inline void _tlog_spin_unlock(unsigned int *lock)
+{
+    __sync_bool_compare_and_swap(lock, 1, 0);
+}
+
+static int _tlog_mkdir(const char *path)
+{
+    char path_c[PATH_MAX];
+    char *path_end;
+    char str;
+    int len;
+    if (access(path, F_OK) == 0) {
+        return 0;
+    }
+
+    strncpy(path_c, path, sizeof(path_c) - 1);
+    len = strnlen(path_c, sizeof(path_c) - 1);
+    path_c[len] = '/';
+    path_c[len + 1] = '\0';
+    path_end = path_c;
+
+    /* create directory recursively */
+    while (*path_end != 0) {
+        if (*path_end != '/') {
+            path_end++;
+            continue;
+        }
+
+        str = *path_end;
+        *path_end = '\0';
+        if (access(path_c, F_OK) == 0) {
+            *path_end = str;
+            path_end++;
+            continue;
+        }
+
+        if (mkdir(path_c, 0750) != 0) {
+            fprintf(stderr, "create directory %s failed, %s\n", path_c, strerror(errno));
+            return -1;
+        }
+
+        *path_end = str;
+        path_end++;
+    }
+
+    return 0;
+}
+
+static struct tm *_tlog_localtime(time_t *timep, struct tm *tm)
+{
+    static time_t last_time = {0};
+    static struct tm last_tm = {0};
+
+    /* localtime_r has a global timezone lock, it's about 8 times slower than gmtime
+     * this code is used to speed up localtime_r call.
+     */
+    _tlog_spin_lock(&tlog_localtime_lock);
+    if (*timep == last_time) {
+        *tm = last_tm;
+    } else {
+        _tlog_spin_unlock(&tlog_localtime_lock);
+        tm = localtime_r(timep, tm);
+        _tlog_spin_lock(&tlog_localtime_lock);
+        if (tm) {
+            last_time = *timep;
+            last_tm = *tm;
+        }
+    }
+    _tlog_spin_unlock(&tlog_localtime_lock);
+
+    return tm;
+}
+
+static int _tlog_getmtime(struct tlog_time *log_mtime, const char *file)
+{
+    struct tm tm;
+    struct stat sb;
+
+    if (stat(file, &sb) != 0) {
+        return -1;
+    }
+
+    if (_tlog_localtime(&sb.st_mtime, &tm) == NULL) {
+        return -1;
+    }
+
+    log_mtime->year = tm.tm_year + 1900;
+    log_mtime->mon = tm.tm_mon + 1;
+    log_mtime->mday = tm.tm_mday;
+    log_mtime->hour = tm.tm_hour;
+    log_mtime->min = tm.tm_min;
+    log_mtime->sec = tm.tm_sec;
+    log_mtime->usec = 0;
+
+    return 0;
+}
+
+static int _tlog_gettime(struct tlog_time *cur_time)
+{
+    struct tm tm;
+    struct timeval tmval;
+
+    if (gettimeofday(&tmval, NULL) != 0) {
+        return -1;
+    }
+
+    if (_tlog_localtime(&tmval.tv_sec, &tm) == NULL) {
+        return -1;
+    }
+
+    cur_time->year = tm.tm_year + 1900;
+    cur_time->mon = tm.tm_mon + 1;
+    cur_time->mday = tm.tm_mday;
+    cur_time->hour = tm.tm_hour;
+    cur_time->min = tm.tm_min;
+    cur_time->sec = tm.tm_sec;
+    cur_time->usec = tmval.tv_usec;
+
+    return 0;
+}
+
+static int _tlog_format(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap)
+{
+    int len = 0;
+    int total_len = 0;
+    struct tlog_time *tm = &info->time;
+
+    if (tlog.multi_log) {
+        /* format prefix */
+        len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5d][%4s][%17s:%-4d] ",
+            tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
+            info->level, info->file, info->line);
+    } else {
+        /* format prefix */
+        len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
+            tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000,
+            info->level, info->file, info->line);
+    }
+
+    if (len < 0 || len == maxlen) {
+        return -1;
+    }
+    buff += len;
+    total_len += len;
+    maxlen -= len;
+
+    /* format log message */
+    len = vsnprintf(buff, maxlen, format, ap);
+    if (len < 0 || len == maxlen) {
+        return -1;
+    }
+    buff += len;
+    total_len += len;
+
+    /* return total length */
+    return total_len;
+}
+
+static int _tlog_log_buffer(char *buff, int maxlen, tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap)
+{
+    int len;
+    struct tlog_info info;
+
+    if (tlog_format == NULL) {
+        return -1;
+    }
+
+    if (level >= TLOG_END) {
+        return -1;
+    }
+
+    info.file = file;
+    info.line = line;
+    info.func = func;
+    info.level = tlog_level_str[level];
+
+    if (_tlog_gettime(&info.time) != 0) {
+        return -1;
+    }
+
+    len = tlog_format(buff, maxlen, &info, userptr, format, ap);
+    if (len < 0) {
+        return -1;
+    }
+
+    /* add new line character*/
+    if (*(buff + len - 1) != '\n' && len + 1 < maxlen - len) {
+        *(buff + len) = '\n';
+        len++;
+    }
+
+    return len;
+}
+
+int tlog_vext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap)
+{
+    int len;
+    int maxlen = 0;
+
+    if (tlog.buff == NULL) {
+        return -1;
+    }
+
+    if (level < tlog_set_level) {
+        return 0;
+    }
+
+    pthread_mutex_lock(&tlog.lock);
+    do {
+        if (tlog.end == tlog.start) {
+            if (tlog.ext_end == 0) {
+                /* if buffer is empty */
+                maxlen = tlog.buffsize - tlog.end;
+            }
+        } else if (tlog.end > tlog.start) {
+            maxlen = tlog.buffsize - tlog.end;
+        } else {
+            /* if reverse */
+            maxlen = tlog.start - tlog.end;
+        }
+
+        /* if free buffer length is less than min line length */
+        if (maxlen < TLOG_MAX_LINE_LEN) {
+            if (tlog.end != tlog.start) {
+                pthread_cond_signal(&tlog.cond);
+            }
+
+            /* if drop message, increase statistics and return */
+            if (tlog.block == 0) {
+                tlog.dropped++;
+                pthread_mutex_unlock(&tlog.lock);
+                return -1;
+            }
+            tlog.waiters++;
+            /* block wait for free buffer */
+            int ret = pthread_cond_wait(&tlog.client_cond, &tlog.lock);
+            tlog.waiters--;
+            if (ret < 0) {
+                pthread_mutex_unlock(&tlog.lock);
+                return -1;
+            }
+        }
+    } while (maxlen < TLOG_MAX_LINE_LEN);
+
+    /* write log to buffer */
+    len = _tlog_log_buffer(tlog.buff + tlog.end, maxlen, level, file, line, func, userptr, format, ap);
+    if (len <= 0) {
+        pthread_mutex_unlock(&tlog.lock);
+        return -1;
+    }
+    tlog.end += len;
+    /* if remain buffer is not enough for a line, move end to start of buffer. */
+    if (tlog.end > tlog.buffsize - TLOG_MAX_LINE_LEN) {
+        tlog.ext_end = tlog.end;
+        tlog.end = 0;
+    }
+    if (tlog.is_wait) {
+        pthread_cond_signal(&tlog.cond);
+    }
+    pthread_mutex_unlock(&tlog.lock);
+    return len;
+}
+
+int tlog_ext(tlog_level level, const char *file, int line, const char *func, void *userptr,
+    const char *format, ...)
+{
+    int len;
+    va_list ap;
+
+    va_start(ap, format);
+    len = tlog_vext(level, file, line, func, userptr, format, ap);
+    va_end(ap);
+
+    return len;
+}
+
+static int _tlog_rename_logfile(const char *gzip_file)
+{
+    char archive_file[PATH_MAX];
+    struct tlog_time logtime;
+    int i = 0;
+
+    if (_tlog_getmtime(&logtime, gzip_file) != 0) {
+        return -1;
+    }
+
+    snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d.gz",
+        tlog.logdir, tlog.logname, logtime.year, logtime.mon, logtime.mday,
+        logtime.hour, logtime.min, logtime.sec);
+
+    while (access(archive_file, F_OK) == 0) {
+        i++;
+        snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d-%d.gz",
+            tlog.logdir, tlog.logname, logtime.year, logtime.mon, logtime.mday,
+            logtime.hour, logtime.min, logtime.sec, i);
+    }
+
+    if (rename(gzip_file, archive_file) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int _tlog_list_dir(const char *path, list_callback callback, void *userptr)
+{
+    DIR *dir = NULL;
+    struct dirent *ent;
+    int ret = 0;
+
+    dir = opendir(path);
+    if (dir == NULL) {
+        fprintf(stderr, "open directory failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    while ((ent = readdir(dir)) != NULL) {
+		if (strncmp(".", ent->d_name, 2) == 0 || strncmp("..", ent->d_name, 3) == 0) {
+			continue;
+        }
+        ret = callback(path, ent, userptr);
+        if (ret != 0) {
+            goto errout;
+        }
+    }
+
+    closedir(dir);
+    return 0;
+errout:
+    if (dir) {
+        closedir(dir);
+        dir = NULL;
+    }
+    return -1;
+}
+
+static int _tlog_count_log_callback(const char *path, struct dirent *entry, void *userptr)
+{
+    int *lognum = (int *)userptr;
+
+    if (strstr(entry->d_name, ".gz") == NULL) {
+        return 0;
+    }
+
+    int len = strnlen(tlog.logname, sizeof(tlog.logname));
+    if (strncmp(tlog.logname, entry->d_name, len) != 0) {
+        return 0;
+    }
+
+    (*lognum)++;
+    return 0;
+}
+
+static int _tlog_get_oldest_callback(const char *path, struct dirent *entry, void *userptr)
+{
+    struct stat sb;
+    char filename[PATH_MAX];
+    struct oldest_log *oldestlog = userptr;
+
+    /* if not a gz file, skip */
+    if (strstr(entry->d_name, ".gz") == NULL) {
+        return 0;
+    }
+
+    /* if not tlog gz file, skip */
+    int len = strnlen(tlog.logname, sizeof(tlog.logname));
+    if (strncmp(tlog.logname, entry->d_name, len) != 0) {
+        return 0;
+    }
+
+    /* get log file mtime */
+    snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
+    if (stat(filename, &sb) != 0) {
+        return -1;
+    }
+
+    if (oldestlog->mtime == 0 || oldestlog->mtime > sb.st_mtime) {
+        oldestlog->mtime = sb.st_mtime;
+        strncpy(oldestlog->name, entry->d_name, sizeof(oldestlog->name));
+        return 0;
+    }
+
+    return 0;
+}
+
+static int _tlog_remove_oldestlog(void)
+{
+    struct oldest_log oldestlog;
+    oldestlog.name[0] = 0;
+    oldestlog.mtime = 0;
+
+    /* get oldest log file name */
+    if (_tlog_list_dir(tlog.logdir, _tlog_get_oldest_callback, &oldestlog) != 0) {
+        return -1;
+    }
+
+    char filename[PATH_MAX];
+    snprintf(filename, sizeof(filename), "%s/%s", tlog.logdir, oldestlog.name);
+
+    /* delete */
+    unlink(filename);
+
+    return 0;
+}
+
+static int _tlog_remove_oldlog(void)
+{
+    int lognum = 0;
+    int i = 0;
+
+    /* get total log file number */
+    if (_tlog_list_dir(tlog.logdir, _tlog_count_log_callback, &lognum) != 0) {
+        fprintf(stderr, "get log file count failed.\n");
+        return -1;
+    }
+
+    /* remove last N log files */
+    for (i = 0; i < lognum - tlog.logcount; i++) {
+        _tlog_remove_oldestlog();
+    }
+
+    return 0;
+}
+
+static void _tlog_log_unlock(void)
+{
+    char lock_file[PATH_MAX];
+    if (tlog.fd_lock <= 0) {
+        return;
+    }
+
+    snprintf(lock_file, sizeof(lock_file), "%s/%s.lock", tlog.logdir, tlog.logname);
+    unlink(lock_file);
+    close(tlog.fd_lock);
+    tlog.fd_lock = -1;
+}
+
+static int _tlog_log_lock(void)
+{
+    char lock_file[PATH_MAX];
+    int fd;
+
+    if (tlog.multi_log == 0) {
+        return 0;
+    }
+
+    snprintf(lock_file, sizeof(lock_file), "%s/%s.lock", tlog.logdir, tlog.logname);
+    fd = open(lock_file, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+    if (fd == -1) {
+        fprintf(stderr, "create pid file failed, %s", strerror(errno));
+        return -1;
+    }
+
+    if (lockf(fd, F_TLOCK, 0) < 0) {
+        goto errout;
+    }
+
+    tlog.fd_lock = fd;
+    return 0;
+
+errout:
+    if (fd > 0) {
+        close(fd);
+    }
+    return -1;
+}
+
+static void _tlog_wait_pid(int wait_hang)
+{
+    int status;
+    if (tlog.zip_pid <= 0) {
+        return;
+    }
+
+    int option = (wait_hang == 0) ? WNOHANG : 0;
+    /* check and obtain gzip process status*/
+    if (waitpid(tlog.zip_pid, &status, option) <= 0) {
+        return;
+    }
+
+    /* gzip process exited */
+    tlog.zip_pid = -1;
+    char gzip_file[PATH_MAX];
+
+    /* rename ziped file */
+    snprintf(gzip_file, sizeof(gzip_file), "%s/%s.pending.gz", tlog.logdir, tlog.logname);
+    if (_tlog_rename_logfile(gzip_file) != 0) {
+        _tlog_log_unlock();
+        return;
+    }
+
+    /* remove oldes file */
+    _tlog_remove_oldlog();
+    _tlog_log_unlock();
+}
+
+static int _tlog_archive_log(void)
+{
+    char gzip_file[PATH_MAX];
+    char gzip_cmd[PATH_MAX];
+    char log_file[PATH_MAX];
+    char pending_file[PATH_MAX];
+
+    snprintf(gzip_file, sizeof(gzip_file), "%s/%s.pending.gz", tlog.logdir, tlog.logname);
+    snprintf(pending_file, sizeof(pending_file), "%s/%s.pending", tlog.logdir, tlog.logname);
+
+    if (_tlog_log_lock() != 0) {
+        return -1;
+    }
+
+    /* if pending.zip exists */
+    if (access(gzip_file, F_OK) == 0) {
+        /* rename it to standard name */
+        if (_tlog_rename_logfile(gzip_file) != 0) {
+            goto errout;
+        }
+    }
+
+    if (access(pending_file, F_OK) != 0) {
+        /* rename current log file to pending */
+        snprintf(log_file, sizeof(log_file), "%s/%s", tlog.logdir, tlog.logname);
+        if (rename(log_file, pending_file) != 0) {
+            goto errout;
+        }
+    }
+
+    /* start gzip process to compress log file */
+    snprintf(gzip_cmd, sizeof(gzip_cmd), "gzip -1 %s", pending_file);
+    if (tlog.zip_pid <= 0) {
+        int pid = vfork();
+        if (pid == 0) {
+            execl("/bin/sh", "sh", "-c", gzip_cmd, NULL);
+            _exit(1);
+        } else if (pid < 0) {
+            goto errout;
+        }
+        tlog.zip_pid = pid;
+    }
+
+    return 0;
+
+errout:
+    _tlog_log_unlock();
+    return -1;
+}
+
+static int _tlog_write_log(char *buff, int bufflen)
+{
+    int len;
+
+    /* if log file size exceeds threshold, start to compress */
+    if (tlog.multi_log) {
+        tlog.filesize = lseek(tlog.fd, 0, SEEK_END);
+    }
+
+    if (tlog.filesize > tlog.logsize && tlog.zip_pid <= 0) {
+        if (tlog.filesize < lseek(tlog.fd, 0, SEEK_END) && tlog.multi_log == 0) {
+            const char *msg = "[Auto enable multi-process write mode, log may be lost, please enable multi-process write mode manually]\n";
+            tlog.multi_log = 1;
+            write(tlog.fd, msg, strlen(msg));
+        }
+        close(tlog.fd);
+        tlog.fd = -1;
+        tlog.filesize = 0;
+        _tlog_archive_log();
+    }
+
+    if (tlog.fd <= 0) {
+        /* open a new log file to write */
+        char logfile[PATH_MAX];
+        if (_tlog_mkdir(tlog.logdir) != 0) {
+            fprintf(stderr, "create log dir %s failed.\n", tlog.logdir);
+            return -1;
+        }
+        snprintf(logfile, sizeof(logfile), "%s/%s", tlog.logdir, tlog.logname);
+        tlog.filesize = 0;
+        tlog.fd = open(logfile, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, 0640);
+        if (tlog.fd < 0) {
+            fprintf(stderr, "open log file %s failed, %s\n", logfile, strerror(errno));
+            return -1;
+        }
+
+        /* get log file size */
+        tlog.filesize = lseek(tlog.fd, 0, SEEK_END);
+    }
+
+    /* output log to screen */
+    if (tlog.logscreen) {
+        write(STDOUT_FILENO, buff, bufflen);
+    }
+
+    /* write log to file */
+    len = write(tlog.fd, buff, bufflen);
+    if (len > 0) {
+        tlog.filesize += len;
+    }
+
+    return len;
+}
+
+static void *_tlog_work(void *arg)
+{
+    int ret = 0;
+    int log_len;
+    int log_extlen;
+    int log_end;
+    int log_extend;
+    int log_dropped;
+    struct timespec tm;
+    time_t now = time(0);
+    time_t last = now;
+
+    while (tlog.run || tlog.end != tlog.start || tlog.ext_end > 0) {
+        log_len = 0;
+        log_end = 0;
+        log_extlen = 0;
+        log_extend = 0;
+
+        /* if compressing */
+        if (tlog.zip_pid > 0) {
+            now = time(0);
+            if (now != last) {
+                /* try to archive compressed file */
+                _tlog_wait_pid(0);
+                last = now;
+            }
+        }
+
+        pthread_mutex_lock(&tlog.lock);
+        if (tlog.end == tlog.start && tlog.ext_end == 0) {
+            /* if buffer is empty, wait */
+            clock_gettime(CLOCK_REALTIME, &tm);
+            tm.tv_sec += 5;
+            tlog.is_wait = 1;
+            ret = pthread_cond_timedwait(&tlog.cond, &tlog.lock, &tm);
+            tlog.is_wait = 0;
+            if (ret < 0 || ret == ETIMEDOUT) {
+                pthread_mutex_unlock(&tlog.lock);
+                if (ret == ETIMEDOUT) {
+                    continue;
+                }
+                sleep(1);
+                continue;
+            }
+        }
+
+        if (tlog.ext_end > 0) {
+            log_len = tlog.ext_end - tlog.start;
+            log_extend = tlog.ext_end;
+        }
+        if (tlog.end < tlog.start) {
+            log_extlen = tlog.end;
+        } else if (tlog.end > tlog.start) {
+            log_len = tlog.end - tlog.start;
+        }
+        log_end = tlog.end;
+        log_dropped = tlog.dropped;
+        tlog.dropped = 0;
+        pthread_mutex_unlock(&tlog.lock);
+
+        /* write log */
+        _tlog_write_log(tlog.buff + tlog.start, log_len);
+        if (log_extlen > 0) {
+            /* write extend buffer log */
+            _tlog_write_log(tlog.buff, log_extlen);
+        }
+
+        if (log_dropped > 0) {
+            /* if there is dropped log, record dropped log number */
+            char dropmsg[TLOG_TMP_LEN];
+            snprintf(dropmsg, sizeof(dropmsg), "[Totoal Dropped %d Messages]\n", log_dropped);
+            _tlog_write_log(dropmsg, strnlen(dropmsg, sizeof(dropmsg)));
+        }
+
+        pthread_mutex_lock(&tlog.lock);
+        /* release finished buffer */
+        tlog.start = log_end;
+        if (log_extend > 0) {
+            tlog.ext_end = 0;
+        }
+
+        if (tlog.waiters > 0) {
+            /* if there are waiters, wakeup */
+            pthread_cond_broadcast(&tlog.client_cond);
+        }
+        pthread_mutex_unlock(&tlog.lock);
+
+        /* sleep for a while to reduce cpu usage */
+        usleep(20 * 1000);
+    }
+    return NULL;
+}
+
+void tlog_setlogscreen(int enable)
+{
+    tlog.logscreen = (enable != 0) ? 1 : 0;
+}
+
+int tlog_reg_format_func(tlog_format_func callback)
+{
+    tlog_format = callback;
+    return 0;
+}
+
+int tlog_setlevel(tlog_level level)
+{
+    if (level >= TLOG_END) {
+        return -1;
+    }
+
+    tlog_set_level = level;
+    return 0;
+}
+
+int tlog_init(const char *logdir, const char *logname, int maxlogsize, int maxlogcount, int block, int buffsize, int multiwrite)
+{
+    pthread_attr_t attr;
+    int ret;
+
+    if (tlog_format != NULL) {
+        fprintf(stderr, "tlog already initilized.\n");
+        return -1;
+    }
+
+    if (buffsize > 0 && buffsize < TLOG_MAX_LINE_LEN * 2) {
+        fprintf(stderr, "buffer size is invalid.\n");
+        return -1;
+    }
+
+    tlog_format = _tlog_format;
+    tlog.logscreen = 0;
+    tlog.buffsize = (buffsize > 0) ? buffsize : TLOG_BUFF_SIZE;
+    tlog.start = 0;
+    tlog.end = 0;
+    tlog.ext_end = 0;
+    tlog.block = (block != 0) ? 1 : 0;
+    tlog.waiters = 0;
+    tlog.dropped = 0;
+    tlog.logsize = (maxlogsize > 0) ? maxlogsize : TLOG_LOG_SIZE;
+    tlog.logcount = (maxlogcount > 0) ? maxlogcount : TLOG_LOG_COUNT;
+    tlog.fd = -1;
+    tlog.filesize = 0;
+    tlog.zip_pid = -1;
+    tlog.logscreen = 0;
+    tlog.multi_log = (multiwrite != 0) ? 1 : 0;
+    tlog.is_wait = 0;
+
+    pthread_attr_init(&attr);
+    pthread_mutex_init(&tlog.lock, 0);
+    pthread_cond_init(&tlog.cond, 0);
+    pthread_cond_init(&tlog.client_cond, 0);
+    tlog.buff = malloc(tlog.buffsize);
+    if (tlog.buff == NULL) {
+        fprintf(stderr, "malloc tlog buffer failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    strncpy(tlog.logdir, logdir, sizeof(tlog.logdir));
+    strncpy(tlog.logname, logname, sizeof(tlog.logname));
+
+    tlog.run = 1;
+    ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
+    if (ret != 0) {
+        fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    return 0;
+errout:
+    if (tlog.buff) {
+        free(tlog.buff);
+        tlog.buff = NULL;
+    }
+    if (tlog.tid > 0) {
+        void *retval = NULL;
+        tlog.run = 0;
+        pthread_join(tlog.tid, &retval);
+    }
+
+    pthread_cond_destroy(&tlog.client_cond);
+    pthread_mutex_destroy(&tlog.lock);
+    pthread_cond_destroy(&tlog.cond);
+    tlog.run = 0;
+
+    return -1;
+}
+
+void tlog_exit(void)
+{
+    if (tlog.tid > 0) {
+        void *ret = NULL;
+        tlog.run = 0;
+        pthread_mutex_lock(&tlog.lock);
+        pthread_cond_signal(&tlog.cond);
+        pthread_mutex_unlock(&tlog.lock);
+        pthread_join(tlog.tid, &ret);
+    }
+
+    if (tlog.zip_pid > 0) {
+        _tlog_wait_pid(1);
+    }
+
+    if (tlog.buff) {
+        free(tlog.buff);
+        tlog.buff = NULL;
+    }
+
+    if (tlog.fd > 0) {
+        close(tlog.fd);
+        tlog.fd = -1;
+    }
+
+    _tlog_log_unlock();
+
+    pthread_cond_destroy(&tlog.client_cond);
+    pthread_mutex_destroy(&tlog.lock);
+    pthread_cond_destroy(&tlog.cond);
+}

+ 89 - 0
tlog.h

@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 Ruilin Peng (Nick) <[email protected]>
+ */
+
+#ifndef TLOG_H
+#define TLOG_H
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus */
+
+typedef enum {
+    TLOG_DEBUG = 0,
+    TLOG_INFO = 1,
+    TLOG_NOTICE = 2,
+    TLOG_WARN = 3,
+    TLOG_ERROR = 4,
+    TLOG_FATAL = 5,
+    TLOG_END = 6
+} tlog_level;
+
+struct tlog_time {
+    int year;
+    int mon;
+    int mday;
+    int hour;
+    int min;
+    int sec;
+    int usec;
+};
+
+struct tlog_info {
+    const char *level;
+    const char *file;
+    const char *func;
+    int line;
+    struct tlog_time time;
+};
+
+/*
+Function:Print log   
+level: Current log Levels  
+format: Log formats  
+*/
+#ifndef BASE_FILE_NAME
+#define BASE_FILE_NAME __FILE__
+#endif
+#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, 0, format, ##__VA_ARGS__)
+
+extern int tlog_ext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, ...) __attribute__((format(printf, 6, 7)));
+extern int tlog_vext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap);
+
+/* set log level */
+extern int tlog_setlevel(tlog_level level);
+
+/* enalbe log to screen */
+extern void tlog_setlogscreen(int enable);
+
+/*
+Function:Initialize log module  
+logdir: Log Output path.    
+logname: Log name.  
+maxlogsize: The maximum size of a single log file.    
+maxlogcount: Number of archived logs.    
+block: Blocked if buffer is not sufficient.    
+buffsize: Buffer size, zero for default (128K) 
+multiwrite: enable multi process write mode. 
+            NOTICE: maxlogsize in all prcesses must be same when enable this mode.  
+ */
+extern int tlog_init(const char *logdir, const char *logname, int maxlogsize, int maxlogcount, int block, int buffsize, int multiwrite);
+
+extern void tlog_exit(void);
+
+/*
+customize log output format
+steps:
+1. define format function, function must be defined as tlog_format_func, use snprintf or vsnprintf format log to buffer
+2. call tlog_reg_format_func to register format function.
+
+read _tlog_format for example.
+*/
+typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap);
+extern int tlog_reg_format_func(tlog_format_func func);
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus */
+#endif // !TLOG_H

+ 34 - 0
util.c

@@ -1,5 +1,9 @@
 #include "util.h"
 #include <time.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 
 unsigned long get_tick_count()
 {
@@ -8,4 +12,34 @@ unsigned long get_tick_count()
     clock_gettime(CLOCK_MONOTONIC, &ts);
 
     return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
+}
+
+char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len)
+{
+	struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr;
+	host[0] = 0;
+	switch (addr_store->ss_family) {
+	case AF_INET: {
+		struct sockaddr_in *addr_in;
+		addr_in = (struct sockaddr_in *)addr;
+		inet_ntop(AF_INET, &addr_in->sin_addr, host, addr_len);
+	} break;
+	case AF_INET6: {
+		struct sockaddr_in6 *addr_in6;
+		addr_in6 = (struct sockaddr_in6 *)addr;
+		if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
+			struct sockaddr_in addr_in4;
+			memset(&addr_in4, 0, sizeof(addr_in4));
+			memcpy(&addr_in4.sin_addr.s_addr, addr_in6->sin6_addr.s6_addr + 12, sizeof(addr_in4.sin_addr.s_addr));
+		} else {
+			inet_ntop(AF_INET6, &addr_in6->sin6_addr, host, addr_len);
+		}
+	} break;
+	default:
+		goto errout;
+		break;
+	}
+	return host;
+errout:
+	return NULL;
 }

+ 4 - 0
util.h

@@ -3,6 +3,10 @@
 #ifndef SMART_DNS_UTIL_H
 #define SMART_DNS_UTIL_H
 
+#include <netdb.h>
+
 unsigned long get_tick_count();
 
+char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len);
+
 #endif