From 9584d1d082b7530efe1e6b2206cc7cbe9dd87968 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sat, 19 May 2018 22:48:14 +0800 Subject: [PATCH] update code --- Makefile | 2 +- dns.h | 2 +- dns_client.c | 552 +++++++++++++++++++---- dns_client.h | 28 +- dns_server.c | 98 +++-- fast_ping.c | 1190 ++++++++++++++++++++++++++------------------------ fast_ping.h | 7 +- smartdns | Bin 73100 -> 0 bytes smartdns.c | 17 +- util.c | 11 + util.h | 8 + 11 files changed, 1193 insertions(+), 722 deletions(-) delete mode 100644 smartdns create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index a8aec48..79ae261 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BIN=smartdns -OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o dns_server.o dns.o +OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o dns_server.o dns.o util.o CFLAGS=-g -O0 -Wall CFLAGS +=-Iinclude CXXFLAGS=-g -O0 -Wall -std=c++11 diff --git a/dns.h b/dns.h index bf9fa3f..b5c62ab 100644 --- a/dns.h +++ b/dns.h @@ -10,7 +10,7 @@ #define DNS_RR_AAAA_LEN 16 #define DNS_MAX_CNAME_LEN 256 #define DNS_IN_PACKSIZE 512 -#define DNS_PACKSIZE (512 * 2) +#define DNS_PACKSIZE (512 * 4) typedef enum dns_rr_type { DNS_RRS_QD = 0, diff --git a/dns_client.c b/dns_client.c index 73fa503..a49bafc 100644 --- a/dns_client.c +++ b/dns_client.c @@ -21,6 +21,8 @@ #include "dns.h" #include "fast_ping.h" #include "hashtable.h" +#include "list.h" +#include "util.h" #include #include #include @@ -56,78 +58,357 @@ struct dns_client { int run; int epoll_fd; + pthread_mutex_t server_list_lock; struct list_head dns_server_list; - pthread_mutex_t map_lock; - DECLARE_HASHTABLE(hostmap, 6); + pthread_mutex_t dns_request_lock; + struct list_head dns_request_list; + struct list_head dns_request_wait_list; + + pthread_mutex_t domain_map_lock; + DECLARE_HASHTABLE(domain_map, 6); int udp; - int tcp; }; + +struct dns_server_info { + struct list_head list; + dns_server_type_t type; + unsigned short ss_family; + socklen_t addr_len; + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr addr; + }; +}; + struct dns_query_struct { - char domain[DNS_MAX_HOSTNAME]; - struct hlist_node host_node; + atomic_t refcnt; + struct list_head dns_request_list; + struct hlist_node domain_node; + char domain[DNS_MAX_CNAME_LEN]; + int dns_request_sent; void *user_ptr; + unsigned long send_tick; + dns_client_callback callback; + struct dns_result result; }; static struct dns_client client; -static dns_client_callback dns_callback; - -static void tv_sub(struct timeval *out, struct timeval *in) +static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol) { - if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */ - --out->tv_sec; - out->tv_usec += 1000000; + struct addrinfo hints; + struct addrinfo *result = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = type; + hints.ai_protocol = protocol; + if (getaddrinfo(host, port, &hints, &result) != 0) { + fprintf(stderr, "get addr info failed. %s\n", strerror(errno)); + goto errout; } - out->tv_sec -= in->tv_sec; + + return result; +errout: + if (result) { + freeaddrinfo(result); + } + return NULL; +} + +int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type) +{ + struct dns_server_info *server_info, *tmp; + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { + continue; + } + + if (server_info->type != server_type) { + continue; + } + + if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { + continue; + } + pthread_mutex_lock(&client.server_list_lock); + return 0; + } + pthread_mutex_unlock(&client.server_list_lock); + return -1; +} + +int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type) +{ + struct dns_server_info *server_info = NULL; + + if (_dns_client_server_exist(gai, server_type) == 0) { + goto errout; + } + + server_info = malloc(sizeof(*server_info)); + if (server_info == NULL) { + goto errout; + } + memset(server_info, 0, sizeof(*server_info)); + server_info->ss_family = gai->ai_family; + server_info->addr_len = gai->ai_addrlen; + server_info->type = server_type; + if (gai->ai_addrlen > sizeof(server_info->addr)) { + goto errout; + } + memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen); + pthread_mutex_lock(&client.server_list_lock); + list_add(&server_info->list, &client.dns_server_list); + pthread_mutex_unlock(&client.server_list_lock); + + if (fast_ping_start(server_ip, 0, 60000, NULL, server_info) != 0) { + goto errout; + } + return 0; +errout: + if (server_info) { + free(server_info); + } + + return -1; +} + +int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type) +{ + struct dns_server_info *server_info, *tmp; + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { + continue; + } + + if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { + continue; + } + list_del(&server_info->list); + pthread_mutex_unlock(&client.server_list_lock); + if (fast_ping_stop(server_ip) != 0) { + printf("stop ping failed.\n"); + } + free(server_info); + return 0; + } + pthread_mutex_unlock(&client.server_list_lock); + return -1; +} + +int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int operate) +{ + char port_s[8]; + int sock_type; + int ret; + struct addrinfo *gai = NULL; + + if (server_type >= DNS_SERVER_TYPE_END) { + return -1; + } + + if (server_type == DNS_SERVER_UDP) { + sock_type = SOCK_DGRAM; + } else { + sock_type = SOCK_STREAM; + } + + snprintf(port_s, 8, "%d", port); + gai = _dns_client_getaddr(server_ip, port_s, sock_type, 0); + if (gai == NULL) { + goto errout; + } + + if (operate == 0) { + ret = _dns_client_server_add(server_ip, gai, server_type); + if (ret != 0) { + goto errout; + } + } else { + ret = _dns_client_server_remove(server_ip, gai, server_type); + if (ret != 0) { + goto errout; + } + } + freeaddrinfo(gai); + return 0; +errout: + if (gai) { + freeaddrinfo(gai); + } + return -1; +} + +int dns_add_server(char *server_ip, int port, dns_server_type_t server_type) +{ + return _dns_client_server_operate(server_ip, port, server_type, 0); +} + +int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type) +{ + return _dns_client_server_operate(server_ip, port, server_type, 1); +} + + +int _dns_client_query_complete(struct dns_query_struct *query) +{ + int ret = -1; + if (query->callback) { + ret = query->callback(query->domain, &query->result, query->user_ptr); + } + + return ret; +} + + +void _dns_client_query_release(struct dns_query_struct *query) +{ + if (!atomic_dec_and_test(&query->refcnt)) { + return; + } + + pthread_mutex_lock(&client.domain_map_lock); + list_del(&query->dns_request_list); + hash_del(&query->domain_node); + pthread_mutex_unlock(&client.domain_map_lock); + _dns_client_query_complete(query); + free(query); +} + +void _dns_client_query_get(struct dns_query_struct *query) +{ + atomic_inc(&query->refcnt); +} + +void dns_client_ping_result(const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, struct timeval *tv, void *userptr) +{ + struct dns_query_struct *query = userptr; + + if (query == NULL) { + return; + } + + unsigned int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100; + + switch (addr->sa_family) { + case AF_INET: { + struct sockaddr_in *addr_in; + addr_in = (struct sockaddr_in *)addr; + if (query->result.ttl_v4 > rtt) { + query->result.ttl_v4 = rtt; + memcpy(query->result.addr_ipv4, &addr_in->sin_addr.s_addr, 4); + } + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6; + addr_in6 = (struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + if (query->result.ttl_v4 > rtt) { + query->result.ttl_v4 = rtt; + memcpy(query->result.addr_ipv4, addr_in6->sin6_addr.s6_addr + 12, 4); + } + } else { + if (query->result.ttl_v6 > rtt) { + query->result.ttl_v6 = rtt; + memcpy(query->result.addr_ipv6, addr_in6->sin6_addr.s6_addr, 16); + } + } + } break; + default: + break; + } + printf("from %15s: seq=%d time=%d\n", host, seqno, rtt); + _dns_client_query_release(query); } void _dns_client_period_run() { + struct dns_query_struct *query, *tmp; + unsigned long now = get_tick_count(); + pthread_mutex_lock(&client.domain_map_lock); + list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list) + { + if (now - query->send_tick > 500) { + } + } + pthread_mutex_unlock(&client.domain_map_lock); + return; } -static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *from, socklen_t from_len) +static struct dns_query_struct *_dns_client_get_request(char *domain) { - int len; - int i; - int j; - int qtype; - int qclass; + struct dns_query_struct *query = NULL; + struct hlist_node *tmp = NULL; + + pthread_mutex_lock(&client.domain_map_lock); + hash_for_each_possible_safe(client.domain_map, query, tmp, domain_node, hash_string(domain)) + { + if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) { + continue; + } + break; + } + pthread_mutex_unlock(&client.domain_map_lock); + + return query; +} + +static int _dns_client_process_answer(char *domain, struct dns_packet *packet) +{ + struct dns_query_struct *query; int ttl; char name[DNS_MAX_CNAME_LEN]; int rr_count; + int i = 0; + int j = 0; struct dns_rrs *rrs = NULL; - unsigned char packet_buff[DNS_PACKSIZE]; - struct dns_packet *packet = (struct dns_packet *)packet_buff; + int ret = -1; + int A_num = 0; - len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len); - if (len != 0) { - printf("decode failed.\n"); + query = _dns_client_get_request(domain); + if (query == NULL) { return -1; } - printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount, - packet->head.nrcount, inpacket_len); - - 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)) { - dns_get_domain(rrs, name, 128, &qtype, &qclass); - printf("domain: %s qtype: %d qclass: %d\n", name, qtype, qclass); - } - for (j = 1; j < DNS_RRS_END; j++) { rrs = dns_get_rrs_start(packet, j, &rr_count); for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { switch (rrs->type) { case DNS_T_A: { unsigned char addr[4]; - dns_get_A(rrs, name, 128, &ttl, addr); + dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); printf("%s %d : %d.%d.%d.%d\n", name, ttl, addr[0], addr[1], addr[2], addr[3]); - dns_callback(name, addr, DNS_T_A, 0); + sprintf(name, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + _dns_client_query_get(query); + if (fast_ping_start(name, 1, 900, dns_client_ping_result, query) != 0) { + _dns_client_query_release(query); + } + A_num++; + } break; + case DNS_T_AAAA: { + unsigned char addr[16]; + dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); + sprintf(name, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], + addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]); + _dns_client_query_get(query); + if (fast_ping_start(name, 1, 900, dns_client_ping_result, query) != 0) { + _dns_client_query_release(query); + } + } break; + case DNS_T_NS: { + char cname[128]; + dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); + printf("NS: %s %d : %s\n", name, ttl, cname); } break; - case DNS_T_NS: case DNS_T_CNAME: { char cname[128]; dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); @@ -139,12 +420,50 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so } } - printf("\n"); + query->dns_request_sent--; + if (query->dns_request_sent <= 0) { + _dns_client_query_release(query); + } - return 0; + return ret; } -static int _dns_client_process(struct dns_query_struct *dns_query, struct timeval *now) +static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *from, socklen_t from_len) +{ + int len; + int i; + int qtype; + int qclass; + char name[DNS_MAX_CNAME_LEN]; + int rr_count; + struct dns_rrs *rrs = NULL; + unsigned char packet_buff[DNS_PACKSIZE]; + struct dns_packet *packet = (struct dns_packet *)packet_buff; + + len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len); + if (len != 0) { + printf("decode failed, packet len = %d\n", inpacket_len); + return -1; + } + + if (packet->head.qr != DNS_OP_IQUERY) { + printf("message type error.\n"); + return -1; + } + + printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount, + packet->head.nrcount, inpacket_len); + + 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)) { + dns_get_domain(rrs, name, DNS_MAX_CNAME_LEN, &qtype, &qclass); + printf("domain: %s qtype: %d qclass: %d\n", name, qtype, qclass); + } + + return _dns_client_process_answer(name, packet); +} + +static int _dns_client_process(struct dns_query_struct *dns_query, unsigned long now) { int len; unsigned char inpacket[DNS_IN_PACKSIZE]; @@ -165,37 +484,35 @@ static void *_dns_client_work(void *arg) struct epoll_event events[DNS_MAX_EVENTS + 1]; int num; int i; - struct timeval last = {0}; - struct timeval now = {0}; - struct timeval diff = {0}; - uint millisec = 0; + unsigned long now = {0}; + unsigned int sleep = 100; + int sleep_time; + unsigned int expect_time = 0; + now = get_tick_count() - sleep; + expect_time = now + sleep; while (client.run) { - diff = now; - tv_sub(&diff, &last); - millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000; - if (millisec >= 1000) { + now = get_tick_count(); + if (now - expect_time >= 0) { _dns_client_period_run(); - last = now; + sleep_time = sleep - (now - expect_time); + if (sleep_time < 0) { + sleep_time = 0; + expect_time = now; + } + expect_time += sleep; } - num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, 1000); + num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time); if (num < 0) { - gettimeofday(&now, 0); usleep(100000); continue; } - if (num == 0) { - gettimeofday(&now, 0); - continue; - } - - gettimeofday(&now, 0); for (i = 0; i < num; i++) { struct epoll_event *event = &events[i]; struct dns_query_struct *dns_query = (struct dns_query_struct *)event->data.ptr; - _dns_client_process(dns_query, &now); + _dns_client_process(dns_query, now); } } @@ -205,17 +522,10 @@ static void *_dns_client_work(void *arg) return NULL; } -static int _dns_client_send_packet(void *packet, int len) +static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len) { - struct sockaddr_in to; int send_len = 0; - socklen_t to_len = sizeof(to); - - memset(&to, 0, sizeof(to)); - to.sin_addr.s_addr = inet_addr("192.168.1.1"); - to.sin_port = htons(53); - - send_len = sendto(client.udp, packet, len, 0, (struct sockaddr *)&to, to_len); + send_len = sendto(client.udp, packet, len, 0, (struct sockaddr *)&server_info->addr, server_info->addr_len); if (send_len != len) { printf("send to server failed."); return -1; @@ -224,7 +534,34 @@ static int _dns_client_send_packet(void *packet, int len) return 0; } -static int _dns_client_send_request(struct dns_query_struct *request, char *doamin) +static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len) +{ + struct dns_server_info *server_info, *tmp; + int ret = 0; + + query->send_tick = get_tick_count(); + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + switch (server_info->type) { + case DNS_SERVER_UDP: + ret = _dns_client_send_udp(server_info, packet, len); + default: + ret = -1; + break; + } + + if (ret != 0) { + continue; + } + + query->dns_request_sent++; + } + pthread_mutex_unlock(&client.server_list_lock); + return 0; +} + +static int _dns_client_send_query(struct dns_query_struct *query, char *doamin) { unsigned char packet_buff[DNS_PACKSIZE]; unsigned char inpacket[DNS_IN_PACKSIZE]; @@ -235,7 +572,7 @@ static int _dns_client_send_request(struct dns_query_struct *request, char *doam memset(&head, 0, sizeof(head)); head.rcode = 0; head.qr = DNS_OP_QUERY; - head.rd = 1; + head.rd = 0; head.ra = 0; head.id = 1; @@ -243,42 +580,60 @@ static int _dns_client_send_request(struct dns_query_struct *request, char *doam dns_add_domain(packet, doamin, DNS_T_A, DNS_C_IN); encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet); if (encode_len <= 0) { - printf("encode request failed.\n"); + printf("encode query failed.\n"); return -1; } - return _dns_client_send_packet(inpacket, encode_len); + return _dns_client_send_packet(query, inpacket, encode_len); } -int dns_client_query(char *domain, void *user_ptr) +int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr) { - struct dns_query_struct *request = NULL; + struct dns_query_struct *query = NULL; int ret = 0; - request = malloc(sizeof(*request)); - if (request == NULL) { - return -1; - } - INIT_HLIST_NODE(&request->host_node); - strncpy(request->domain, domain, DNS_MAX_CNAME_LEN); - request->user_ptr = user_ptr; - ret =_dns_client_send_request(request, domain); - if (ret != 0) { + query = malloc(sizeof(*query)); + if (query == NULL) { goto errout; } - free(request); + memset(query, 0, sizeof(*query)); + INIT_HLIST_NODE(&query->domain_node); + INIT_LIST_HEAD(&query->dns_request_list); + atomic_set(&query->refcnt, 0); + strncpy(query->domain, domain, DNS_MAX_CNAME_LEN); + query->user_ptr = user_ptr; + query->callback = callback; + query->result.ttl_v4 = -1; + query->result.ttl_v6 = -1; + + _dns_client_query_get(query); + ret = _dns_client_send_query(query, domain); + if (ret != 0) { + goto errout_del_list; + } + + pthread_mutex_lock(&client.domain_map_lock); + list_add_tail(&query->dns_request_list, &client.dns_request_list); + hash_add(client.domain_map, &query->domain_node, hash_string(domain)); + pthread_mutex_unlock(&client.domain_map_lock); + return 0; +errout_del_list: + atomic_dec(&query->refcnt); + pthread_mutex_lock(&client.domain_map_lock); + list_del(&query->dns_request_list); + hash_del(&query->domain_node); + pthread_mutex_unlock(&client.domain_map_lock); errout: - if (request) { - free(request); + if (query) { + free(query); } return -1; } -int dns_register_callback(dns_client_callback callback) +int dns_client_query_raw(char *domain, unsigned char *raw, int raw_len, void *user_ptr) { - dns_callback = callback; - return 0; + return -1; } static struct addrinfo *_dns_server_getaddr(const char *host, const char *port, int type, int protocol) @@ -322,7 +677,7 @@ int dns_client_socket(void) int fd = -1; struct addrinfo *gai = NULL; - gai = _dns_server_getaddr(NULL, "54", SOCK_DGRAM, 0); + gai = _dns_server_getaddr(NULL, "53", SOCK_DGRAM, 0); if (gai == NULL) { fprintf(stderr, "get address failed.\n"); goto errout; @@ -383,11 +738,17 @@ int dns_client_init() goto errout; } - pthread_mutex_init(&client.map_lock, 0); - hash_init(client.hostmap); + pthread_mutex_init(&client.server_list_lock, 0); + INIT_LIST_HEAD(&client.dns_server_list); + + pthread_mutex_init(&client.domain_map_lock, 0); + hash_init(client.domain_map); + INIT_LIST_HEAD(&client.dns_request_wait_list); + INIT_LIST_HEAD(&client.dns_request_list); + client.epoll_fd = epollfd; - if (dns_client_start()) { + if (dns_client_start()) { fprintf(stderr, "start client failed.\n"); goto errout; } @@ -400,15 +761,17 @@ errout: pthread_join(client.tid, &retval); } - if (fd > 0) { - close(fd); + if (client.udp > 0) { + close(client.udp); + client.udp = -1; } if (epollfd) { close(epollfd); } - pthread_mutex_destroy(&client.map_lock); + pthread_mutex_destroy(&client.server_list_lock); + pthread_mutex_destroy(&client.domain_map_lock); return -1; } @@ -425,5 +788,6 @@ void dns_client_exit() close(client.udp); } - pthread_mutex_destroy(&client.map_lock); + pthread_mutex_destroy(&client.server_list_lock); + pthread_mutex_destroy(&client.domain_map_lock); } \ No newline at end of file diff --git a/dns_client.h b/dns_client.h index cb876ab..c40bf51 100644 --- a/dns_client.h +++ b/dns_client.h @@ -1,13 +1,35 @@ #ifndef _SMART_DNS_CLIENT_H #define _SMART_DNS_CLIENT_H +#include "dns.h" + +typedef enum { + DNS_SERVER_UDP, + DNS_SERVER_TCP, + DNS_SERVER_HTTP, + DNS_SERVER_TYPE_END, +} dns_server_type_t; + +struct dns_result { + char alias[DNS_MAX_CNAME_LEN]; + unsigned long ttl_v4; + unsigned char addr_ipv4[4]; + unsigned long ttl_v6; + unsigned char addr_ipv6[16]; +}; + int dns_client_init(void); -typedef int (*dns_client_callback)(char *domain, unsigned char *addr, int addr_type, void *user_ptr); -int dns_register_callback(dns_client_callback callback); +typedef int (*dns_client_callback)(char *domain, struct dns_result *result, void *user_ptr); -int dns_client_query(char *domain, void *user_ptr); +int dns_client_query(char *domain, dns_client_callback callback, void *user_ptr); + +int dns_client_query_raw(char *domain, unsigned char *raw, int raw_len, void *user_ptr); void dns_client_exit(void); +int dns_add_server(char *server_ip, int port, dns_server_type_t server_type); + +int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type); + #endif diff --git a/dns_server.c b/dns_server.c index ee93ca2..cca2a5b 100644 --- a/dns_server.c +++ b/dns_server.c @@ -18,6 +18,8 @@ #include "dns_server.h" #include "dns.h" +#include "util.h" +#include "atomic.h" #include "hashtable.h" #include "list.h" #include "dns_client.h" @@ -52,6 +54,7 @@ struct dns_server { }; struct dns_request { + atomic_t refcnt; struct hlist_node map; char domain[DNS_MAX_CNAME_LEN]; unsigned short qtype; @@ -72,15 +75,6 @@ struct dns_request { static struct dns_server server; -static void tv_sub(struct timeval *out, struct timeval *in) -{ - if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */ - --out->tv_sec; - out->tv_usec += 1000000; - } - out->tv_sec -= in->tv_sec; -} - void _dns_server_period_run() { return; @@ -177,6 +171,7 @@ static int _dns_add_rrs(struct dns_packet *packet, struct dns_request *request) return ret; } + static int _dns_reply(struct dns_request *request) { unsigned char inpacket[DNS_IN_PACKSIZE]; @@ -220,6 +215,40 @@ static int _dns_reply(struct dns_request *request) return 0; } + +static int dns_server_resolve_callback(char *domain, struct dns_result *result, void *user_ptr) +{ + struct dns_request *request = user_ptr; + + if (user_ptr == NULL) { + return -1; + } + + + memcpy(request->ipv4_addr, result->addr_ipv4, 4); + //memcpy(request->ipv6_addr, result->addr_ipv6, 16); + request->qtype = DNS_T_A; + + printf("----------------%s--%d.%d.%d.%d-\n", domain, + request->ipv4_addr[0], + request->ipv4_addr[1], + request->ipv4_addr[2], + request->ipv4_addr[3]); + _dns_reply(request); + + if (!atomic_dec_and_test(&request->refcnt)) { + return 0; + + } + + printf("free query server %p\n", request); + memset(request, 0, sizeof(*request)); + free(request); + + return 0; +} + + static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *from, socklen_t from_len) { int decode_len; @@ -279,9 +308,10 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so break; } - dns_client_query(request->domain, request); + printf("query server %p\n", request); + atomic_set(&request->refcnt, 1); + dns_client_query(request->domain, dns_server_resolve_callback, request); - free(request); return 0; errout: if (request) { @@ -291,7 +321,7 @@ errout: return ret; } -static int _dns_server_process(struct timeval *now) +static int _dns_server_process(unsigned long now) { int len; unsigned char inpacket[DNS_IN_PACKSIZE]; @@ -312,33 +342,34 @@ int dns_server_run(void) struct epoll_event events[DNS_MAX_EVENTS + 1]; int num; int i; - struct timeval last = {0}; - struct timeval now = {0}; - struct timeval diff = {0}; - uint millisec = 0; + unsigned long now = {0}; + int sleep = 1000; + int sleep_time = 0; + unsigned long expect_time = 0; - while (server.run) { - diff = now; - tv_sub(&diff, &last); - millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000; - if (millisec >= 1000) { - _dns_server_period_run(); - last = now; - } + now = get_tick_count() - sleep; + expect_time = now + sleep; + while (server.run) { + now = get_tick_count(); + if (now - expect_time >= 0) { + _dns_server_period_run(); + sleep_time = sleep - (now - expect_time); + if (sleep_time < 0) { + sleep_time = 0; + + } + expect_time += sleep; + } - num = epoll_wait(server.epoll_fd, events, DNS_MAX_EVENTS, 1000); + num = epoll_wait(server.epoll_fd, events, DNS_MAX_EVENTS, sleep_time); if (num < 0) { - gettimeofday(&now, 0); usleep(100000); continue; } if (num == 0) { - gettimeofday(&now, 0); continue; } - - gettimeofday(&now, 0); for (i = 0; i < num; i++) { struct epoll_event *event = &events[i]; if (event->data.fd != server.fd) { @@ -346,7 +377,7 @@ int dns_server_run(void) continue; } - _dns_server_process(&now); + _dns_server_process(now); } } @@ -429,11 +460,6 @@ errout: return -1; } -static int dns_server_resolve_callback(char *domain, unsigned char *addr, int addr_type, void *user_ptr) -{ - return 0; -} - int dns_server_init(void) { pthread_attr_t attr; @@ -465,8 +491,6 @@ int dns_server_init(void) server.fd = fd; server.run = 1; - dns_register_callback(dns_server_resolve_callback); - if (dns_server_start() != 0) { fprintf(stderr, "start service failed.\n"); goto errout; diff --git a/fast_ping.c b/fast_ping.c index f8d3e0c..8a53dbe 100755 --- a/fast_ping.c +++ b/fast_ping.c @@ -1,7 +1,7 @@ /************************************************************************* -* -* Copyright (C) 2018 Ruilin Peng (Nick) . -* + * + * Copyright (C) 2018 Ruilin Peng (Nick) . + * * smartdns is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -19,8 +19,8 @@ #include "fast_ping.h" #include "atomic.h" #include "hashtable.h" -#include #include +#include #include #include #include @@ -42,770 +42,820 @@ #define ICMP_INPACKET_SIZE 1024 struct fast_ping_packet_msg { - struct timeval tv; + struct timeval tv; }; struct fast_ping_packet { - union { - struct icmp icmp; - struct icmp6_hdr icmp6; - }; - struct fast_ping_packet_msg msg; + union { + struct icmp icmp; + struct icmp6_hdr icmp6; + }; + struct fast_ping_packet_msg msg; }; struct ping_host_struct { - atomic_t ref; - struct hlist_node host_node; - struct hlist_node addr_node; - int type; + atomic_t ref; + struct hlist_node host_node; + struct hlist_node addr_node; + int type; - void *userptr; - char host[PING_MAX_HOSTLEN]; + void *userptr; + fast_ping_result ping_callback; + char host[PING_MAX_HOSTLEN]; - int fd; - unsigned int seq; - struct timeval last; - int interval; - int timeout; - int send; - struct sockaddr_storage addr; - socklen_t addr_len; - struct fast_ping_packet packet; + int fd; + unsigned int seq; + struct timeval last; + int interval; + int timeout; + int count; + int send; + struct sockaddr addr; + socklen_t addr_len; + struct fast_ping_packet packet; }; struct fast_ping_struct { - int run; - pthread_t tid; - pthread_mutex_t lock; - unsigned short ident; + int run; + pthread_t tid; + pthread_mutex_t lock; + unsigned short ident; - int epoll_fd; - int fd_icmp; - struct ping_host_struct icmp_host; - int fd_icmp6; - struct ping_host_struct icmp6_host; + int epoll_fd; + int fd_icmp; + struct ping_host_struct icmp_host; + int fd_icmp6; + struct ping_host_struct icmp6_host; - pthread_mutex_t map_lock; - DECLARE_HASHTABLE(hostmap, 6); - DECLARE_HASHTABLE(addrmap, 6); + pthread_mutex_t map_lock; + DECLARE_HASHTABLE(hostmap, 6); + DECLARE_HASHTABLE(addrmap, 6); }; static struct fast_ping_struct ping; -static fast_ping_result ping_callback; uint16_t _fast_ping_checksum(uint16_t *header, size_t len) { - uint32_t sum = 0; - int i; + uint32_t sum = 0; + int i; - for (i = 0; i < len / sizeof(uint16_t); i++) { - sum += ntohs(header[i]); - } + for (i = 0; i < len / sizeof(uint16_t); i++) { + sum += ntohs(header[i]); + } - return htons(~((sum >> 16) + (sum & 0xffff))); -} - -void fast_ping_result_callback(fast_ping_result result) -{ - ping_callback = result; + return htons(~((sum >> 16) + (sum & 0xffff))); } void _fast_ping_install_filter_v6(int sock) { - struct icmp6_filter icmp6_filter; - ICMP6_FILTER_SETBLOCKALL(&icmp6_filter); - ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter); - setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter)); + struct icmp6_filter icmp6_filter; + ICMP6_FILTER_SETBLOCKALL(&icmp6_filter); + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter); + setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter)); - static int once; - static struct sock_filter insns[] = { - BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */ - BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */ - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */ - BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */ - BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */ - }; - static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns }; + static int once; + static struct sock_filter insns[] = { + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */ + BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */ + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */ + BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */ + BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */ + }; + static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns}; - if (once) { - return; - } - once = 1; + if (once) { + return; + } + once = 1; - /* Patch bpflet for current identifier. */ - insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1); + /* Patch bpflet for current identifier. */ + insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1); - if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { - perror("WARNING: failed to install socket filter\n"); - } + if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { + perror("WARNING: failed to install socket filter\n"); + } } void _fast_ping_install_filter_v4(int sock) { - static int once; - static struct sock_filter insns[] = { - BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */ - BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */ - BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */ - BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */ - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */ - BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */ - BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */ - }; + static int once; + static struct sock_filter insns[] = { + BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */ + BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */ + BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */ + BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */ + BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */ + BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */ + }; - static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns }; + static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns}; - if (once) { - return; - } - once = 1; + if (once) { + return; + } + once = 1; - /* Patch bpflet for current identifier. */ - insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1); + /* Patch bpflet for current identifier. */ + insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1); - if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { - perror("WARNING: failed to install socket filter\n"); - } + if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { + perror("WARNING: failed to install socket filter\n"); + } } static struct addrinfo *_fast_ping_getaddr(const char *host, int type, int protocol) { - struct addrinfo hints; - struct addrinfo *result = NULL; + struct addrinfo hints; + struct addrinfo *result = NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = type; - hints.ai_protocol = protocol; - if (getaddrinfo(host, NULL, &hints, &result) != 0) { - fprintf(stderr, "get addr info failed. %s\n", strerror(errno)); - goto errout; - } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = type; + hints.ai_protocol = protocol; + if (getaddrinfo(host, NULL, &hints, &result) != 0) { + fprintf(stderr, "get addr info failed. %s\n", strerror(errno)); + goto errout; + } - return result; + return result; errout: - if (result) { - freeaddrinfo(result); - } - return NULL; + if (result) { + freeaddrinfo(result); + } + return NULL; } static int _fast_ping_getdomain(const char *host) { - struct addrinfo hints; - struct addrinfo *result = NULL; - int domain = -1; + struct addrinfo hints; + struct addrinfo *result = NULL; + int domain = -1; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - if (getaddrinfo(host, NULL, &hints, &result) != 0) { - fprintf(stderr, "get addr info failed. %s\n", strerror(errno)); - goto errout; - } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + if (getaddrinfo(host, NULL, &hints, &result) != 0) { + fprintf(stderr, "get addr info failed. %s\n", strerror(errno)); + goto errout; + } - domain = result->ai_family; + domain = result->ai_family; - freeaddrinfo(result); + freeaddrinfo(result); - return domain; + return domain; errout: - if (result) { - freeaddrinfo(result); - } - return -1; + if (result) { + freeaddrinfo(result); + } + return -1; } static void _fast_ping_host_get(struct ping_host_struct *ping_host) { - atomic_inc(&ping_host->ref); + atomic_inc(&ping_host->ref); } static void _fast_ping_host_put(struct ping_host_struct *ping_host) { - pthread_mutex_lock(&ping.map_lock); - if (atomic_dec_and_test(&ping_host->ref)) { - hlist_del(&ping_host->host_node); - hlist_del(&ping_host->addr_node); - } else { - ping_host = NULL; - } - pthread_mutex_unlock(&ping.map_lock); + pthread_mutex_lock(&ping.map_lock); + if (atomic_dec_and_test(&ping_host->ref)) { + hlist_del(&ping_host->host_node); + hlist_del(&ping_host->addr_node); + } else { + ping_host = NULL; + } + pthread_mutex_unlock(&ping.map_lock); - if (ping_host == NULL) { - return ; - } + if (ping_host == NULL) { + return; + } - free(ping_host); + free(ping_host); +} + +static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host) +{ + if (atomic_dec_and_test(&ping_host->ref)) { + hlist_del(&ping_host->host_node); + hlist_del(&ping_host->addr_node); + } else { + ping_host = NULL; + } + + if (ping_host == NULL) { + return; + } + + free(ping_host); } static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host) { - struct fast_ping_packet *packet = &ping_host->packet; - struct icmp6_hdr *icmp6 = &packet->icmp6; - int len = 0; + struct fast_ping_packet *packet = &ping_host->packet; + struct icmp6_hdr *icmp6 = &packet->icmp6; + int len = 0; - ping_host->seq++; - memset(icmp6, 0, sizeof(*icmp6)); - icmp6->icmp6_type = ICMP6_ECHO_REQUEST; - icmp6->icmp6_code = 0; - icmp6->icmp6_cksum = 0; - icmp6->icmp6_id = getpid(); - icmp6->icmp6_seq = htons(ping_host->seq); + ping_host->seq++; + memset(icmp6, 0, sizeof(*icmp6)); + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_id = getpid(); + icmp6->icmp6_seq = htons(ping_host->seq); - gettimeofday(&packet->msg.tv, 0); - icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet)); + gettimeofday(&packet->msg.tv, 0); + 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); - if (len < 0 || len != sizeof(struct fast_ping_packet)) { - fprintf(stderr, "sendto %s\n", strerror(errno)); - goto errout; - } + len = sendto(ping_host->fd, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len); + if (len < 0 || len != sizeof(struct fast_ping_packet)) { + fprintf(stderr, "sendto %s\n", strerror(errno)); + goto errout; + } - return 0; + return 0; errout: - return -1; + return -1; } static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host) { - struct fast_ping_packet *packet = &ping_host->packet; - struct icmp *icmp = &packet->icmp; - int len; + struct fast_ping_packet *packet = &ping_host->packet; + struct icmp *icmp = &packet->icmp; + int len; - ping_host->seq++; - memset(icmp, 0, sizeof(*icmp)); - icmp->icmp_type = ICMP_ECHO; - icmp->icmp_code = 0; - icmp->icmp_cksum = 0; - icmp->icmp_id = ping.ident; - icmp->icmp_seq = htons(ping_host->seq); + ping_host->seq++; + memset(icmp, 0, sizeof(*icmp)); + icmp->icmp_type = ICMP_ECHO; + icmp->icmp_code = 0; + icmp->icmp_cksum = 0; + icmp->icmp_id = ping.ident; + icmp->icmp_seq = htons(ping_host->seq); - gettimeofday(&packet->msg.tv, 0); - icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet)); + gettimeofday(&packet->msg.tv, 0); + 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); - if (len < 0 || len != sizeof(struct fast_ping_packet)) { - fprintf(stderr, "sendto %s\n", strerror(errno)); - goto errout; - } + len = sendto(ping_host->fd, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len); + if (len < 0 || len != sizeof(struct fast_ping_packet)) { + fprintf(stderr, "sendto %s\n", strerror(errno)); + goto errout; + } - return 0; + return 0; errout: - return -1; + return -1; } static int _fast_ping_sendping(struct ping_host_struct *ping_host) { - int ret = -1; + int ret = -1; - if (ping_host->type == AF_INET) { - ret = _fast_ping_sendping_v4(ping_host); - } else if (ping_host->type == AF_INET6) { - ret = _fast_ping_sendping_v6(ping_host); - } + if (ping_host->type == AF_INET) { + ret = _fast_ping_sendping_v4(ping_host); + } else if (ping_host->type == AF_INET6) { + ret = _fast_ping_sendping_v6(ping_host); + } - if (ret != 0) { - return ret; - } + if (ret != 0) { + return ret; + } - ping_host->send = 1; - gettimeofday(&ping_host->last, 0); + ping_host->send = 1; + gettimeofday(&ping_host->last, 0); - return 0; + return 0; } static int _fast_ping_create_sock(int protocol) { - int fd = -1; - struct ping_host_struct *icmp_host = NULL; - struct epoll_event event; + int fd = -1; + struct ping_host_struct *icmp_host = NULL; + struct epoll_event event; - switch (protocol) { - case IPPROTO_ICMP: - fd = socket(AF_INET, SOCK_RAW, protocol); - if (fd < 0) { - fprintf(stderr, "create icmp socket failed.\n"); - goto errout; - } - _fast_ping_install_filter_v4(fd); - icmp_host = &ping.icmp_host; - break; - case IPPROTO_ICMPV6: - fd = socket(AF_INET6, SOCK_RAW, protocol); - if (fd < 0) { - fprintf(stderr, "create icmp socket failed.\n"); - goto errout; - } - _fast_ping_install_filter_v6(fd); - icmp_host = &ping.icmp6_host; - break; - } + switch (protocol) { + case IPPROTO_ICMP: + fd = socket(AF_INET, SOCK_RAW, protocol); + if (fd < 0) { + fprintf(stderr, "create icmp socket failed.\n"); + goto errout; + } + _fast_ping_install_filter_v4(fd); + icmp_host = &ping.icmp_host; + break; + case IPPROTO_ICMPV6: + fd = socket(AF_INET6, SOCK_RAW, protocol); + if (fd < 0) { + fprintf(stderr, "create icmp socket failed.\n"); + goto errout; + } + _fast_ping_install_filter_v6(fd); + icmp_host = &ping.icmp6_host; + break; + } - event.events = EPOLLIN; - event.data.ptr = icmp_host; - if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { - goto errout; - } + event.events = EPOLLIN; + event.data.ptr = icmp_host; + if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { + goto errout; + } - icmp_host->fd = fd; - icmp_host->type = AF_PACKET; - return fd; + icmp_host->fd = fd; + icmp_host->type = AF_PACKET; + return fd; errout: - close(fd); - return -1; + close(fd); + return -1; } static int _fast_ping_create_icmp(int protocol) { - int fd = 0; - int *set_fd = NULL; + int fd = 0; + int *set_fd = NULL; - pthread_mutex_lock(&ping.lock); - switch (protocol) { - case IPPROTO_ICMP: - set_fd = &ping.fd_icmp; - break; - case IPPROTO_ICMPV6: - set_fd = &ping.fd_icmp6; - break; - default: - goto errout; - break; - } + pthread_mutex_lock(&ping.lock); + switch (protocol) { + case IPPROTO_ICMP: + set_fd = &ping.fd_icmp; + break; + case IPPROTO_ICMPV6: + set_fd = &ping.fd_icmp6; + break; + default: + goto errout; + break; + } - if (*set_fd > 0) { - goto out; - } + if (*set_fd > 0) { + goto out; + } - fd = _fast_ping_create_sock(protocol); - if (fd < 0) { - goto errout; - } + fd = _fast_ping_create_sock(protocol); + if (fd < 0) { + goto errout; + } - *set_fd = fd; + *set_fd = fd; out: - pthread_mutex_unlock(&ping.lock); - return *set_fd; + pthread_mutex_unlock(&ping.lock); + return *set_fd; errout: - if (fd > 0) { - close(fd); - } - pthread_mutex_unlock(&ping.lock); - return -1; -} - -int fast_ping_start(const char *host, int timeout, void *userptr) -{ - struct ping_host_struct *ping_host = NULL; - struct addrinfo *gai = NULL; - int domain = -1; - int icmp_proto = 0; - uint32_t hostkey; - uint32_t addrkey; - int fd = -1; - - domain = _fast_ping_getdomain(host); - if (domain < 0) { - return -1; - } - - switch (domain) { - case AF_INET: - icmp_proto = IPPROTO_ICMP; - break; - case AF_INET6: - icmp_proto = IPPROTO_ICMPV6; - break; - default: - return -1; - break; - } - - fd = _fast_ping_create_icmp(icmp_proto); - if (fd < 0) { - goto errout; - } - - gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto); - if (gai == NULL) { - goto errout; - } - - ping_host = malloc(sizeof(*ping_host)); - if (ping_host == NULL) { - goto errout; - } - - int interval = 1000; - memset(ping_host, 0, sizeof(*ping_host)); - strncpy(ping_host->host, host, PING_MAX_HOSTLEN); - ping_host->type = domain; - ping_host->fd = fd; - ping_host->timeout = timeout; - ping_host->interval = (timeout > interval) ? timeout : interval; - memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen); - ping_host->addr_len = gai->ai_addrlen; - - atomic_set(&ping_host->ref, 0); - - hostkey = hash_string(ping_host->host); - addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0); - pthread_mutex_lock(&ping.map_lock); - _fast_ping_host_get(ping_host); - hash_add(ping.hostmap, &ping_host->host_node, hostkey); - hash_add(ping.addrmap, &ping_host->addr_node, addrkey); - pthread_mutex_unlock(&ping.map_lock); - - freeaddrinfo(gai); - - _fast_ping_sendping(ping_host); - return 0; -errout: - if (fd > 0) { + if (fd > 0) { close(fd); } - - if (gai) { - freeaddrinfo(gai); - } + pthread_mutex_unlock(&ping.lock); + return -1; +} - if (ping_host) { - free(ping_host); - } +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) +{ + if (result == PING_RESULT_RESPONSE) { + double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0; + printf("from %15s: seq=%d time=%.3f\n", host, seqno, rtt); + } else if (result == PING_RESULT_TIMEOUT) { + printf("from %15s: seq=%d timeout\n", host, seqno); + } +} - return -1; +int fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr) +{ + struct ping_host_struct *ping_host = NULL; + struct addrinfo *gai = NULL; + int domain = -1; + int icmp_proto = 0; + uint32_t hostkey; + uint32_t addrkey; + int fd = -1; + + domain = _fast_ping_getdomain(host); + if (domain < 0) { + return -1; + } + + switch (domain) { + case AF_INET: + icmp_proto = IPPROTO_ICMP; + break; + case AF_INET6: + icmp_proto = IPPROTO_ICMPV6; + break; + default: + return -1; + break; + } + + fd = _fast_ping_create_icmp(icmp_proto); + if (fd < 0) { + goto errout; + } + + gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto); + if (gai == NULL) { + goto errout; + } + + ping_host = malloc(sizeof(*ping_host)); + if (ping_host == NULL) { + goto errout; + } + + int interval = 1000; + memset(ping_host, 0, sizeof(*ping_host)); + strncpy(ping_host->host, host, PING_MAX_HOSTLEN); + ping_host->type = domain; + ping_host->fd = fd; + ping_host->timeout = timeout; + ping_host->count = count; + ping_host->userptr = userptr; + if (ping_callback) { + ping_host->ping_callback = ping_callback; + } else { + ping_host->ping_callback = fast_ping_print_result; + } + ping_host->interval = (timeout > interval) ? timeout : interval; + memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen); + ping_host->addr_len = gai->ai_addrlen; + + atomic_set(&ping_host->ref, 0); + + hostkey = hash_string(ping_host->host); + addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0); + pthread_mutex_lock(&ping.map_lock); + _fast_ping_host_get(ping_host); + hash_add(ping.hostmap, &ping_host->host_node, hostkey); + hash_add(ping.addrmap, &ping_host->addr_node, addrkey); + pthread_mutex_unlock(&ping.map_lock); + + freeaddrinfo(gai); + + _fast_ping_sendping(ping_host); + return 0; +errout: + if (fd > 0) { + close(fd); + } + + if (gai) { + freeaddrinfo(gai); + } + + if (ping_host) { + free(ping_host); + } + + return -1; } int fast_ping_stop(const char *host) { - struct ping_host_struct *ping_host; - uint32_t key; - key = hash_string(host); - pthread_mutex_lock(&ping.map_lock); - hash_for_each_possible(ping.hostmap, ping_host, host_node, key) - { - if (strncmp(host, ping_host->host, PING_MAX_HOSTLEN) == 0) { - break; - } - } - if (ping_host == NULL) { - pthread_mutex_unlock(&ping.map_lock); - return -1; - } - pthread_mutex_unlock(&ping.map_lock); - _fast_ping_host_put(ping_host); - return 0; + struct ping_host_struct *ping_host; + uint32_t key; + key = hash_string(host); + pthread_mutex_lock(&ping.map_lock); + hash_for_each_possible(ping.hostmap, ping_host, host_node, key) + { + if (strncmp(host, ping_host->host, PING_MAX_HOSTLEN) == 0) { + break; + } + } + if (ping_host == NULL) { + pthread_mutex_unlock(&ping.map_lock); + return -1; + } + pthread_mutex_unlock(&ping.map_lock); + _fast_ping_host_put(ping_host); + return 0; } static void tv_sub(struct timeval *out, struct timeval *in) { - if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */ - --out->tv_sec; - out->tv_usec += 1000000; - } - out->tv_sec -= in->tv_sec; + if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */ + --out->tv_sec; + out->tv_usec += 1000000; + } + 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) { - int icmp_len; - struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data; - struct icmp6_hdr *icmp6 = &packet->icmp6; - struct timeval tvresult = *tvrecv; + int icmp_len; + struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data; + struct icmp6_hdr *icmp6 = &packet->icmp6; + struct timeval tvresult = *tvrecv; - if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) { - return -1; - } + if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) { + return -1; + } - icmp_len = data_len; - if (icmp_len < 16) { - return -1; - } + icmp_len = data_len; + if (icmp_len < 16) { + return -1; + } - if (icmp6->icmp6_id != ping.ident) { - return -1; - } + if (icmp6->icmp6_id != ping.ident) { + return -1; + } - struct timeval *tvsend = &packet->msg.tv; - tv_sub(&tvresult, tvsend); - ping_callback(ping_host->host, PING_RESULT_RESPONSE, ping_host->seq, &tvresult, ping_host->userptr); + struct timeval *tvsend = &packet->msg.tv; + tv_sub(&tvresult, tvsend); - return 0; + 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) { - struct ip *ip = (struct ip *)packet_data; - struct fast_ping_packet *packet; - struct icmp *icmp; - struct timeval tvresult = *tvrecv; - int hlen; - int icmp_len; + struct ip *ip = (struct ip *)packet_data; + struct fast_ping_packet *packet; + struct icmp *icmp; + struct timeval tvresult = *tvrecv; + int hlen; + int icmp_len; - if (ip->ip_p != IPPROTO_ICMP) { - return -1; - } + if (ip->ip_p != IPPROTO_ICMP) { + return -1; + } - hlen = ip->ip_hl << 2; - packet = (struct fast_ping_packet *)(packet_data + hlen); - icmp = &packet->icmp; - icmp_len = data_len - hlen; + hlen = ip->ip_hl << 2; + packet = (struct fast_ping_packet *)(packet_data + hlen); + icmp = &packet->icmp; + icmp_len = data_len - hlen; - if (icmp_len < 16) { - return -1; - } + if (icmp_len < 16) { + return -1; + } - if (icmp->icmp_type != ICMP_ECHOREPLY) { - return -1; - } + if (icmp->icmp_type != ICMP_ECHOREPLY) { + return -1; + } - if (icmp->icmp_id != ping.ident) { - return -1; - } + if (icmp->icmp_id != ping.ident) { + return -1; + } - struct timeval *tvsend = &packet->msg.tv; - tv_sub(&tvresult, tvsend); + struct timeval *tvsend = &packet->msg.tv; + tv_sub(&tvresult, tvsend); + if (ping_host->ping_callback) { + ping_host->ping_callback(ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tvresult, ping_host->userptr); + } - ping_callback(ping_host->host, PING_RESULT_RESPONSE, ping_host->seq, &tvresult, ping_host->userptr); - - return 0; + return 0; } static int _fast_ping_recvping(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv) { - if (ping_host->type == AF_INET6) { - if (_fast_ping_icmp6_packet(ping_host, inpacket, len, tvrecv)) { - goto errout; - } - } else if (ping_host->type == AF_INET) { + if (ping_host->type == AF_INET6) { + if (_fast_ping_icmp6_packet(ping_host, inpacket, len, tvrecv)) { + goto errout; + } + } else if (ping_host->type == AF_INET) { + if (_fast_ping_icmp_packet(ping_host, inpacket, len, tvrecv)) { + goto errout; + } + } - if (_fast_ping_icmp_packet(ping_host, inpacket, len, tvrecv)) { - goto errout; - } - } - - return 0; + return 0; errout: - return -1; + 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; - break; - } - return 0; + 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 0; errout: - return -1; + return -1; } +#endif static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now) { - int len; - u_char inpacket[ICMP_INPACKET_SIZE]; - struct sockaddr_storage from; - struct ping_host_struct *recv_ping_host; - socklen_t from_len = sizeof(from); - uint32_t addrkey; + int len; + u_char inpacket[ICMP_INPACKET_SIZE]; + struct sockaddr_storage from; + struct ping_host_struct *recv_ping_host; + socklen_t from_len = sizeof(from); + uint32_t addrkey; - len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len); - if (len < 0) { - fprintf(stderr, "recvfrom failed, %s\n", strerror(errno)); - goto errout; - } + len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len); + if (len < 0) { + fprintf(stderr, "recvfrom failed, %s\n", strerror(errno)); + goto errout; + } - addrkey = jhash(&from, from_len, 0); - pthread_mutex_lock(&ping.map_lock); - hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey) - { - if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0) { - break; - } - } - pthread_mutex_unlock(&ping.map_lock); + addrkey = jhash(&from, from_len, 0); + pthread_mutex_lock(&ping.map_lock); + hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey) + { + if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0) { + break; + } + } + pthread_mutex_unlock(&ping.map_lock); - if (recv_ping_host == NULL) { - return -1; - } + if (recv_ping_host == NULL) { + return -1; + } - recv_ping_host->send = 0; + recv_ping_host->send = 0; - _fast_ping_recvping(recv_ping_host, inpacket, len, now); - return 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) { + _fast_ping_host_put(recv_ping_host); + } + return 0; errout: - return -1; + return -1; } static void _fast_ping_period_run() { - struct ping_host_struct *ping_host; - struct hlist_node *tmp; - int i = 0; - struct timeval now; - struct timeval interval; - uint64_t millisecond; - gettimeofday(&now, 0); + struct ping_host_struct *ping_host; + struct hlist_node *tmp; + int i = 0; + struct timeval now; + struct timeval interval; + uint64_t millisecond; + gettimeofday(&now, 0); - pthread_mutex_lock(&ping.map_lock); - hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node) - { - interval = now; - tv_sub(&interval, &ping_host->last); - millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000; - if (millisecond > ping_host->timeout && ping_host->send == 1) { - ping_callback(ping_host->host, PING_RESULT_TIMEOUT, ping_host->seq, &interval, ping_host->userptr); - ping_host->send = 0; - } - if (millisecond >= ping_host->interval) { - _fast_ping_sendping(ping_host); - } - } - pthread_mutex_unlock(&ping.map_lock); + pthread_mutex_lock(&ping.map_lock); + hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node) + { + interval = now; + tv_sub(&interval, &ping_host->last); + millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000; + if (millisecond > ping_host->timeout && ping_host->send == 1) { + ping_host->ping_callback(ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval, ping_host->userptr); + ping_host->send = 0; + } + + if (millisecond < ping_host->interval) { + continue; + } + if (ping_host->count >= 0) { + ping_host->count--; + } + if (ping_host->count == 0) { + _fast_ping_host_put_locked(ping_host); + continue; + } + + _fast_ping_sendping(ping_host); + } + pthread_mutex_unlock(&ping.map_lock); } static void *_fast_ping_work(void *arg) { - struct epoll_event events[PING_MAX_EVENTS + 1]; - int num; - int i; - struct timeval last = { 0 }; - struct timeval now = { 0 }; - struct timeval diff = {0}; - uint millisec = 0; + struct epoll_event events[PING_MAX_EVENTS + 1]; + int num; + int i; + struct timeval last = {0}; + struct timeval now = {0}; + struct timeval diff = {0}; + uint millisec = 0; - while (ping.run) { - diff = now; - tv_sub(&diff, &last); - millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000; - if (millisec >= 100) { - _fast_ping_period_run(); - last = now; - } + while (ping.run) { + diff = now; + tv_sub(&diff, &last); + millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000; + if (millisec >= 100) { + _fast_ping_period_run(); + last = now; + } - num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100); - if (num < 0) { - gettimeofday(&now, 0); - usleep(100000); - continue; - } + num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100); + if (num < 0) { + gettimeofday(&now, 0); + usleep(100000); + continue; + } - if (num == 0) { - gettimeofday(&now, 0); - continue; - } + if (num == 0) { + gettimeofday(&now, 0); + continue; + } - gettimeofday(&now, 0); - for (i = 0; i < num; i++) { - struct epoll_event *event = &events[i]; - struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr; - _fast_ping_process(ping_host, &now); - } - } + gettimeofday(&now, 0); + for (i = 0; i < num; i++) { + struct epoll_event *event = &events[i]; + struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr; + _fast_ping_process(ping_host, &now); + } + } - close(ping.epoll_fd); - ping.epoll_fd = -1; + close(ping.epoll_fd); + ping.epoll_fd = -1; - return NULL; + return NULL; } int fast_ping_init() { - pthread_attr_t attr; - int epollfd = -1; - int ret; + pthread_attr_t attr; + int epollfd = -1; + int ret; - if (ping.epoll_fd > 0) { - return -1; - } + if (ping.epoll_fd > 0) { + return -1; + } - memset(&ping, 0, sizeof(ping)); - pthread_attr_init(&attr); + memset(&ping, 0, sizeof(ping)); + pthread_attr_init(&attr); - epollfd = epoll_create1(EPOLL_CLOEXEC); - if (epollfd < 0) { - fprintf(stderr, "create epoll failed, %s\n", strerror(errno)); - goto errout; - } + epollfd = epoll_create1(EPOLL_CLOEXEC); + if (epollfd < 0) { + fprintf(stderr, "create epoll failed, %s\n", strerror(errno)); + 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; - } + ping.run = 1; + ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL); + if (ret != 0) { + fprintf(stderr, "create ping work thread failed, %s\n", strerror(errno)); + goto errout; + } - pthread_mutex_init(&ping.map_lock, 0); - pthread_mutex_init(&ping.lock, 0); - hash_init(ping.hostmap); - hash_init(ping.addrmap); - ping.epoll_fd = epollfd; - ping.ident = getpid(); + pthread_mutex_init(&ping.map_lock, 0); + pthread_mutex_init(&ping.lock, 0); + hash_init(ping.hostmap); + hash_init(ping.addrmap); + ping.epoll_fd = epollfd; + ping.ident = getpid(); - return 0; + return 0; errout: - if (ping.tid > 0) { - void *retval = NULL; - ping.run = 0; - pthread_join(ping.tid, &retval); - } + if (ping.tid > 0) { + void *retval = NULL; + ping.run = 0; + pthread_join(ping.tid, &retval); + } - if (epollfd) { - close(epollfd); - } + if (epollfd) { + close(epollfd); + } - pthread_mutex_destroy(&ping.lock); - pthread_mutex_destroy(&ping.map_lock); + pthread_mutex_destroy(&ping.lock); + pthread_mutex_destroy(&ping.map_lock); - return -1; + return -1; } void fast_ping_exit() { - if (ping.tid > 0) { - void *ret = NULL; - ping.run = 0; - pthread_join(ping.tid, &ret); - } + if (ping.tid > 0) { + void *ret = NULL; + ping.run = 0; + pthread_join(ping.tid, &ret); + } - if (ping.fd_icmp > 0) { - close(ping.fd_icmp); - ping.fd_icmp = -1; - } + if (ping.fd_icmp > 0) { + close(ping.fd_icmp); + ping.fd_icmp = -1; + } - if (ping.fd_icmp6 > 0) { - close(ping.fd_icmp6); - ping.fd_icmp6 = -1; - } + if (ping.fd_icmp6 > 0) { + close(ping.fd_icmp6); + ping.fd_icmp6 = -1; + } - pthread_mutex_destroy(&ping.lock); - pthread_mutex_destroy(&ping.map_lock); + pthread_mutex_destroy(&ping.lock); + pthread_mutex_destroy(&ping.map_lock); } \ No newline at end of file diff --git a/fast_ping.h b/fast_ping.h index ac9a41c..22dc4ae 100755 --- a/fast_ping.h +++ b/fast_ping.h @@ -2,7 +2,7 @@ #define FAST_PING_H #include - +#include #ifdef __cpluscplus extern "C" { #endif @@ -18,10 +18,9 @@ typedef enum { PING_RESULT_TIMEOUT = 2, } FAST_PING_RESULT; -typedef void (*fast_ping_result)(const char *host, FAST_PING_RESULT result, int seqno, struct timeval *tv, void *userptr); -void fast_ping_result_callback(fast_ping_result 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); -int fast_ping_start(const char *host, int timeout, void *userptr); +int fast_ping_start(const char *host, int count, int timeout, fast_ping_result ping_callback, void *userptr); int fast_ping_stop(const char *host); diff --git a/smartdns b/smartdns deleted file mode 100644 index afbfbebdc80e94ad5e1bacee7a3d43035e5778b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73100 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 B#47** diff --git a/smartdns.c b/smartdns.c index 08d9aab..cffcd67 100755 --- a/smartdns.c +++ b/smartdns.c @@ -21,18 +21,10 @@ #include "dns_server.h" #include "hashtable.h" #include "list.h" +#include "tlog.h" #include #include -void smartdns_ping_result(const char *host, FAST_PING_RESULT result, int seqno, struct timeval *tv, void *userptr) -{ - if (result == PING_RESULT_RESPONSE) { - double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0; - printf("%16s: seq=%d time=%.3f\n", host, seqno, rtt); - } else if (result == PING_RESULT_TIMEOUT) { - printf("%16s: seq=%d timeout\n", host, seqno); - } -} int smartdns_init() { @@ -44,8 +36,6 @@ int smartdns_init() goto errout; } - fast_ping_result_callback(smartdns_ping_result); - ret = dns_server_init(); if (ret != 0) { fprintf(stderr, "start dns server failed.\n"); @@ -58,7 +48,10 @@ int smartdns_init() goto errout; } - return 0; + //dns_add_server("192.168.1.1", 53, DNS_SERVER_UDP); + dns_add_server("114.114.114.114", 53, DNS_SERVER_UDP); + dns_add_server("123.207.137.88", 53, DNS_SERVER_UDP); + return 0; errout: return -1; diff --git a/util.c b/util.c new file mode 100644 index 0000000..dcfa9e0 --- /dev/null +++ b/util.c @@ -0,0 +1,11 @@ +#include "util.h" +#include + +unsigned long get_tick_count() +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); +} \ No newline at end of file diff --git a/util.h b/util.h new file mode 100644 index 0000000..7700d4d --- /dev/null +++ b/util.h @@ -0,0 +1,8 @@ + + +#ifndef SMART_DNS_UTIL_H +#define SMART_DNS_UTIL_H + +unsigned long get_tick_count(); + +#endif \ No newline at end of file