update code
This commit is contained in:
3
Makefile
3
Makefile
@@ -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
|
||||||
|
|
||||||
|
|||||||
60
dns_client.c
60
dns_client.c
@@ -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");
|
||||||
|
|||||||
12
dns_server.c
12
dns_server.c
@@ -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);
|
||||||
|
|
||||||
|
|||||||
253
fast_ping.c
253
fast_ping.c
@@ -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:
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
27
smartdns.c
27
smartdns.c
@@ -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
908
tlog.c
Normal 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
89
tlog.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
util.c
34
util.c
@@ -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()
|
||||||
{
|
{
|
||||||
@@ -9,3 +13,33 @@ unsigned long get_tick_count()
|
|||||||
|
|
||||||
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
4
util.h
@@ -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
|
||||||
Reference in New Issue
Block a user