diff --git a/Makefile b/Makefile index d312368..8cb6fe9 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BIN=smartdns -OBJS=smartdns.o fast_ping.o lib/bitops.o +OBJS=smartdns.o fast_ping.o lib/bitops.o dns_client.o CFLAGS=-g -O0 -Wall CFLAGS +=-Iinclude CXXFLAGS=-g -O0 -Wall -std=c++11 diff --git a/dns-client.c b/dns-client.c deleted file mode 100644 index 120d286..0000000 --- a/dns-client.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "dns-client.h" - diff --git a/dns-client.h b/dns-client.h deleted file mode 100644 index d414314..0000000 --- a/dns-client.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SMART_DNS_CLIENT_H -#define _SMART_DNS_CLIENT_H - - - -#endif \ No newline at end of file diff --git a/dns.h b/dns.h new file mode 100644 index 0000000..ce446ee --- /dev/null +++ b/dns.h @@ -0,0 +1,39 @@ +#ifndef _DNS_HEAD_H +#define _DNS_HEAD_H + +#pragma pack(push, 1) + +struct dns_head { + unsigned short id; // identification number + unsigned char rd : 1; // recursion desired + unsigned char tc : 1; // truncated message + unsigned char aa : 1; // authoritive answer + unsigned char opcode : 4; // purpose of message + unsigned char qr : 1; // query/response flag + unsigned char rcode : 4; // response code + unsigned char cd : 1; // checking disabled + unsigned char ad : 1; // authenticated data + unsigned char z : 1; // its z! reserved + unsigned char ra : 1; // recursion available + unsigned short qd_count; // number of question entries + unsigned short an_count; // number of answer entries + unsigned short ns_count; // number of authority entries + unsigned short nr_count; // number of resource entries +}; + +struct dns_qds { + unsigned short type; + unsigned short classes; +}; + +struct dns_rrs { + unsigned short type; + unsigned short classes; + unsigned int ttl; + unsigned short rd_length; + char rd_data[0]; +}; + +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/dns_client.c b/dns_client.c new file mode 100644 index 0000000..5e460cc --- /dev/null +++ b/dns_client.c @@ -0,0 +1,196 @@ +#include "dns_client.h" +#include "atomic.h" +#include "fast_ping.h" +#include "hashtable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DNS_MAX_HOSTNAME 256 + +#define DNS_INPACKET_SIZE 512 + +#define DNS_MAX_EVENTS 64 + +#define DNS_HOSTNAME_LEN 128 + +struct dns_query_server { + int fd; + int type; + char host[DNS_HOSTNAME_LEN]; + list_head list; +}; + +struct dns_client { + pthread_t tid; + int run; + int epoll_fd; + + list_head dns_server_list; + + pthread_mutex_t map_lock; + DECLARE_HASHTABLE(hostmap, 6); + + int udp; + int tcp; +}; +struct dns_query_struct { + char host[DNS_MAX_HOSTNAME]; + struct hlist_node host_node; +}; + +static struct dns_client client; + +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_client_period_run() +{ +} + +static int _dns_client_process(struct dns_query_struct *dns_query, struct timeval *now) +{ + int len; + u_char inpacket[DNS_INPACKET_SIZE]; + struct sockaddr_storage from; + socklen_t from_len = sizeof(from); + + len = recvfrom(client.udp, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len); + if (len < 0) { + fprintf(stderr, "recvfrom failed, %s\n", strerror(errno)); + goto errout; + } + + return 0; +errout: + return -1; +} + +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; + + while (client.run) { + diff = now; + tv_sub(&diff, &last); + millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000; + if (millisec >= 100) { + _dns_client_period_run(); + last = now; + } + + num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, 100); + 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); + } + } + + close(client.epoll_fd); + client.epoll_fd = -1; + + return NULL; +} + +int dns_client_init() +{ + pthread_attr_t attr; + int epollfd = -1; + int ret; + + if (client.epoll_fd > 0) { + return -1; + } + + memset(&client, 0, sizeof(client)); + pthread_attr_init(&attr); + + epollfd = epoll_create1(EPOLL_CLOEXEC); + if (epollfd < 0) { + fprintf(stderr, "create epoll failed, %s\n", strerror(errno)); + goto errout; + } + + client.run = 1; + 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.map_lock, 0); + hash_init(client.hostmap); + client.epoll_fd = epollfd; + + return 0; +errout: + if (client.tid > 0) { + void *retval = NULL; + client.run = 0; + pthread_join(client.tid, &retval); + } + + if (epollfd) { + close(epollfd); + } + + pthread_mutex_destroy(&client.map_lock); + + return -1; +} + +int dns_client_query(char *host) +{ + return 0; +errout: + return -1; +} + +void dns_client_exit() +{ + if (client.tid > 0) { + void *ret = NULL; + client.run = 0; + pthread_join(client.tid, &ret); + } + + pthread_mutex_destroy(&client.map_lock); +} \ No newline at end of file diff --git a/dns_client.h b/dns_client.h new file mode 100644 index 0000000..e95a922 --- /dev/null +++ b/dns_client.h @@ -0,0 +1,10 @@ +#ifndef _SMART_DNS_CLIENT_H +#define _SMART_DNS_CLIENT_H + +int dns_client_init(void); + +int dns_client_query(char *host); + +void dns_client_exit(void); + +#endif diff --git a/fast_ping.c b/fast_ping.c index b7f8e2f..b3462c5 100755 --- a/fast_ping.c +++ b/fast_ping.c @@ -417,7 +417,7 @@ int fast_ping_start(const char *host, int timeout, void *userptr) ping_host = malloc(sizeof(*ping_host)); if (ping_host == NULL) { - goto errout; + goto errout; } int interval = 1000; @@ -477,7 +477,7 @@ int fast_ping_stop(const char *host) return 0; } -void tv_sub(struct timeval *out, struct timeval *in) +static void tv_sub(struct timeval *out, struct timeval *in) { if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */ --out->tv_sec; diff --git a/smartdns.c b/smartdns.c index 9db5a02..cb4ecca 100755 --- a/smartdns.c +++ b/smartdns.c @@ -26,6 +26,12 @@ int smartdns_init() fast_ping_result_callback(smartdns_ping_result); + ret = dns_client_init(); + if (ret != 0) { + fprintf(stderr, "start dns client failed.\n"); + goto errout; + } + return 0; errout: @@ -49,6 +55,8 @@ int smartdns_run() void smartdns_exit() { fast_ping_exit(); + + dns_client_exit(); } struct data {