forked from aarond10/https_dns_proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dns_poller.c
115 lines (100 loc) · 3.17 KB
/
dns_poller.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <sys/socket.h>
#include <sys/types.h>
#include <ares.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dns_poller.h"
#include "logging.h"
static void sock_cb(struct ev_loop *loop, ev_io *w, int revents) {
dns_poller_t *d = (dns_poller_t *)w->data;
ares_process_fd(d->ares, (revents & EV_READ) ? w->fd : ARES_SOCKET_BAD,
(revents & EV_WRITE) ? w->fd : ARES_SOCKET_BAD);
}
static void sock_state_cb(void *data, int fd, int read, int write) {
dns_poller_t *d = (dns_poller_t *)data;
if (!read && !write) {
ev_io_stop(d->loop, &d->fd[fd]);
d->fd[fd].fd = 0;
} else if (d->fd[fd].fd != 0) {
ev_io_stop(d->loop, &d->fd[fd]);
ev_io_init(&d->fd[fd], sock_cb, fd,
(read ? EV_READ : 0) | (write ? EV_WRITE : 0));
d->fd[fd].data = d;
ev_io_start(d->loop, &d->fd[fd]);
} else {
ev_io_init(&d->fd[fd], sock_cb, fd,
(read ? EV_READ : 0) | (write ? EV_WRITE : 0));
d->fd[fd].data = d;
ev_io_start(d->loop, &d->fd[fd]);
}
}
static void ares_cb(void *arg, int status, int timeouts, struct hostent *h) {
dns_poller_t *d = (dns_poller_t *)arg;
if (status != ARES_SUCCESS) {
WLOG("DNS lookup failed: %d", status);
} else if (!h || h->h_length < 1) {
WLOG("No hosts.");
} else {
d->cb(d->hostname, d->cb_data, (struct sockaddr_in *)h->h_addr_list[0]);
}
}
static void timer_cb(struct ev_loop *loop, ev_timer *w, int revents) {
dns_poller_t *d = (dns_poller_t *)w->data;
ares_gethostbyname(d->ares, d->hostname, AF_INET, ares_cb, d);
}
void dns_poller_init(dns_poller_t *d, struct ev_loop *loop,
const char *bootstrap_dns, const char *hostname,
int interval_seconds, dns_poller_cb cb, void *cb_data) {
int i;
for (i = 0; i < FD_SETSIZE; i++) {
d->fd[i].fd = 0;
}
int r;
ares_library_init(ARES_LIB_INIT_ALL);
struct ares_options options;
options.sock_state_cb = sock_state_cb;
options.sock_state_cb_data = d;
options.servers = NULL;
options.nservers = 0;
char *csv = strdup(bootstrap_dns);
if (!csv) {
FLOG("Out of mem");
}
char *last = NULL;
char *ipstr = strtok_r(csv, ",", &last);
while (ipstr) {
options.servers = (struct in_addr *)realloc(
options.servers, sizeof(struct in_addr)*(options.nservers + 1));
if (!options.servers) {
FLOG("Out of mem");
}
if (ares_inet_pton(AF_INET, ipstr,
&options.servers[options.nservers++]) != 1) {
FLOG("Failed to parse '%s'", ipstr);
}
ipstr = strtok_r(NULL, ",", &last);
}
free(csv);
if ((r = ares_init_options(
&d->ares, &options,
ARES_OPT_SOCK_STATE_CB | ARES_OPT_SERVERS)) != ARES_SUCCESS) {
FLOG("ares_init_options error: %s", ares_strerror(r));
}
free(options.servers);
d->loop = loop;
d->hostname = hostname;
d->cb = cb;
d->cb_data = cb_data;
ev_timer_init(&d->timer, timer_cb, 0, interval_seconds);
d->timer.data = d;
ev_timer_start(d->loop, &d->timer);
}
void dns_poller_cleanup(dns_poller_t *d) {
ev_timer_stop(d->loop, &d->timer);
ares_destroy(d->ares);
ares_library_cleanup();
}