update code

This commit is contained in:
Nick Peng
2018-05-21 08:09:03 +08:00
parent 9584d1d082
commit 72dd4e6cd3
11 changed files with 1257 additions and 164 deletions

View File

@@ -1,8 +1,9 @@
BIN=smartdns 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=-g -O0 -Wall
CFLAGS +=-Iinclude CFLAGS +=-Iinclude
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
CXXFLAGS=-g -O0 -Wall -std=c++11 CXXFLAGS=-g -O0 -Wall -std=c++11
CXXFLAGS +=-Iinclude CXXFLAGS +=-Iinclude

View File

@@ -23,6 +23,7 @@
#include "hashtable.h" #include "hashtable.h"
#include "list.h" #include "list.h"
#include "util.h" #include "util.h"
#include "tlog.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <linux/filter.h> #include <linux/filter.h>
@@ -73,6 +74,7 @@ struct dns_client {
struct dns_server_info { struct dns_server_info {
struct list_head list; struct list_head list;
struct ping_host_struct *ping_host;
dns_server_type_t type; dns_server_type_t type;
unsigned short ss_family; unsigned short ss_family;
socklen_t addr_len; socklen_t addr_len;
@@ -85,6 +87,7 @@ struct dns_server_info {
struct dns_query_struct { struct dns_query_struct {
atomic_t refcnt; atomic_t refcnt;
unsigned short sid;
struct list_head dns_request_list; struct list_head dns_request_list;
struct hlist_node domain_node; struct hlist_node domain_node;
char domain[DNS_MAX_CNAME_LEN]; char domain[DNS_MAX_CNAME_LEN];
@@ -96,6 +99,7 @@ struct dns_query_struct {
}; };
static struct dns_client client; 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) 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; goto errout;
} }
memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen); memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen);
if (fast_ping_start(server_ip, 0, 60000, NULL, server_info) == NULL) {
goto errout;
}
pthread_mutex_lock(&client.server_list_lock); pthread_mutex_lock(&client.server_list_lock);
list_add(&server_info->list, &client.dns_server_list); list_add(&server_info->list, &client.dns_server_list);
pthread_mutex_unlock(&client.server_list_lock); pthread_mutex_unlock(&client.server_list_lock);
if (fast_ping_start(server_ip, 0, 60000, NULL, server_info) != 0) {
goto errout;
}
return 0; return 0;
errout: errout:
if (server_info) { 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); list_del(&server_info->list);
pthread_mutex_unlock(&client.server_list_lock); 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"); printf("stop ping failed.\n");
} }
free(server_info); free(server_info);
@@ -279,7 +284,10 @@ void _dns_client_query_release(struct dns_query_struct *query)
list_del(&query->dns_request_list); list_del(&query->dns_request_list);
hash_del(&query->domain_node); hash_del(&query->domain_node);
pthread_mutex_unlock(&client.domain_map_lock); pthread_mutex_unlock(&client.domain_map_lock);
tlog(TLOG_ERROR, "-------------%p, %d\n", query, atomic_read(&query->refcnt));
_dns_client_query_complete(query); _dns_client_query_complete(query);
//TODO double free BUG://
memset(query, 0, sizeof(*query));
free(query); free(query);
} }
@@ -288,7 +296,7 @@ void _dns_client_query_get(struct dns_query_struct *query)
atomic_inc(&query->refcnt); 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; struct dns_query_struct *query = userptr;
@@ -344,13 +352,16 @@ void _dns_client_period_run()
return; 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 dns_query_struct *query = NULL;
struct hlist_node *tmp = 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); 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) { if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) {
continue; continue;
@@ -374,7 +385,7 @@ static int _dns_client_process_answer(char *domain, struct dns_packet *packet)
int ret = -1; int ret = -1;
int A_num = 0; int A_num = 0;
query = _dns_client_get_request(domain); query = _dns_client_get_request(packet->head.id, domain);
if (query == NULL) { if (query == NULL) {
return -1; 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]); 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]); sprintf(name, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
_dns_client_query_get(query); _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); _dns_client_query_release(query);
} }
A_num++; 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], 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]); addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
_dns_client_query_get(query); _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); _dns_client_query_release(query);
} }
} break; } break;
@@ -451,8 +462,8 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
return -1; return -1;
} }
printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount, 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.nrcount, inpacket_len, packet->head.id);
rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &rr_count); 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)) { 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.qr = DNS_OP_QUERY;
head.rd = 0; head.rd = 0;
head.ra = 0; head.ra = 0;
head.id = 1; head.id = query->sid;
dns_packet_init(packet, DNS_PACKSIZE, &head); dns_packet_init(packet, DNS_PACKSIZE, &head);
dns_add_domain(packet, doamin, DNS_T_A, DNS_C_IN); 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; struct dns_query_struct *query = NULL;
int ret = 0; int ret = 0;
unsigned int key = 0;
query = malloc(sizeof(*query)); query = malloc(sizeof(*query));
if (query == NULL) { if (query == NULL) {
@@ -605,6 +617,7 @@ int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr)
query->callback = callback; query->callback = callback;
query->result.ttl_v4 = -1; query->result.ttl_v4 = -1;
query->result.ttl_v6 = -1; query->result.ttl_v6 = -1;
query->sid = atomic_inc_return(&dns_client_sid);
_dns_client_query_get(query); _dns_client_query_get(query);
ret = _dns_client_send_query(query, domain); 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; goto errout_del_list;
} }
key = hash_string(domain);
key = jhash(&query->sid, sizeof(query->sid), key);
pthread_mutex_lock(&client.domain_map_lock); pthread_mutex_lock(&client.domain_map_lock);
list_add_tail(&query->dns_request_list, &client.dns_request_list); 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); pthread_mutex_unlock(&client.domain_map_lock);
return 0; return 0;
@@ -730,14 +745,6 @@ int dns_client_init()
goto errout; 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); pthread_mutex_init(&client.server_list_lock, 0);
INIT_LIST_HEAD(&client.dns_server_list); INIT_LIST_HEAD(&client.dns_server_list);
@@ -747,6 +754,13 @@ int dns_client_init()
INIT_LIST_HEAD(&client.dns_request_list); INIT_LIST_HEAD(&client.dns_request_list);
client.epoll_fd = epollfd; 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()) { if (dns_client_start()) {
fprintf(stderr, "start client failed.\n"); fprintf(stderr, "start client failed.\n");

View File

@@ -20,6 +20,7 @@
#include "dns.h" #include "dns.h"
#include "util.h" #include "util.h"
#include "atomic.h" #include "atomic.h"
#include "tlog.h"
#include "hashtable.h" #include "hashtable.h"
#include "list.h" #include "list.h"
#include "dns_client.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; } break;
case DNS_T_A: 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; break;
case DNS_T_AAAA: 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; break;
default: default:
break; break;
@@ -224,7 +225,6 @@ static int dns_server_resolve_callback(char *domain, struct dns_result *result,
return -1; return -1;
} }
memcpy(request->ipv4_addr, result->addr_ipv4, 4); memcpy(request->ipv4_addr, result->addr_ipv4, 4);
//memcpy(request->ipv6_addr, result->addr_ipv6, 16); //memcpy(request->ipv6_addr, result->addr_ipv6, 16);
request->qtype = DNS_T_A; 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)); memset(request, 0, sizeof(*request));
free(request); free(request);
@@ -308,7 +308,7 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so
break; break;
} }
printf("query server %p\n", request); tlog(TLOG_ERROR, "query server %p\n", request);
atomic_set(&request->refcnt, 1); atomic_set(&request->refcnt, 1);
dns_client_query(request->domain, dns_server_resolve_callback, request); dns_client_query(request->domain, dns_server_resolve_callback, request);

View File

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

View File

@@ -9,6 +9,7 @@ extern "C" {
typedef enum { typedef enum {
FAST_PING_ICMP = 1, FAST_PING_ICMP = 1,
FAST_PING_ICMP6 = 2,
FAST_PING_TCP, FAST_PING_TCP,
FAST_PING_UDP FAST_PING_UDP
} FAST_PING_TYPE; } FAST_PING_TYPE;
@@ -18,11 +19,12 @@ typedef enum {
PING_RESULT_TIMEOUT = 2, PING_RESULT_TIMEOUT = 2,
} FAST_PING_RESULT; } 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(); int fast_ping_init();

View File

@@ -91,6 +91,29 @@ static inline void atomic_dec( atomic_t *v )
(void)__sync_fetch_and_sub(&v->counter, 1); (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 * @brief Decrement and test
* @param v pointer of type atomic_t * @param v pointer of type atomic_t

View File

@@ -25,12 +25,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
int smartdns_init() int smartdns_init()
{ {
int ret; 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) { if (ret != 0) {
fprintf(stderr, "start ping failed.\n"); fprintf(stderr, "start ping failed.\n");
goto errout; goto errout;
@@ -48,9 +53,10 @@ int smartdns_init()
goto errout; 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("114.114.114.114", 53, DNS_SERVER_UDP);
dns_add_server("123.207.137.88", 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; return 0;
errout: errout:
@@ -65,10 +71,9 @@ int smartdns_run()
void smartdns_exit() void smartdns_exit()
{ {
fast_ping_exit(); fast_ping_exit();
dns_client_exit(); dns_client_exit();
dns_server_exit(); dns_server_exit();
tlog_exit();
} }
struct data { struct data {
@@ -193,13 +198,21 @@ int rbtree_test()
} }
#endif #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 main(int argc, char *argv[])
{ {
int ret; int ret;
atexit(smartdns_exit); atexit(smartdns_exit);
signal(SIGABRT, sig_handle);
ret = smartdns_init(); ret = smartdns_init();
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "init smartdns failed.\n"); fprintf(stderr, "init smartdns failed.\n");
goto errout; goto errout;

908
tlog.c Normal file
View File

@@ -0,0 +1,908 @@
/*
* Copyright (C) 2018 Ruilin Peng (Nick) <pymumu@gmail.com>
*/
#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
tlog.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2018 Ruilin Peng (Nick) <pymumu@gmail.com>
*/
#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;
};
/*
FunctionPrint 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);
/*
FunctionInitialize 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
util.c
View File

@@ -1,5 +1,9 @@
#include "util.h" #include "util.h"
#include <time.h> #include <time.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
unsigned long get_tick_count() unsigned long get_tick_count()
{ {
@@ -8,4 +12,34 @@ unsigned long get_tick_count()
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); 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
util.h
View File

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