-
Notifications
You must be signed in to change notification settings - Fork 12
/
asyncdns.c
144 lines (124 loc) · 3.35 KB
/
asyncdns.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* Async DNS resolver
* Copyright (C) 2009-2010 Unix Solutions Ltd.
*
* Released under MIT license.
* See LICENSE-MIT.txt for license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "log.h"
/* FreeBSD have problems with pathread_cancel so do not use async resolver */
#ifdef __FreeBSD__
int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
msec_timeout = msec_timeout;
active = active;
struct hostent *hostinfo = gethostbyname(host);
if (hostinfo == NULL) {
int local_h_errno = h_errno;
LOGf("gethostbyname(%s) returned %s", host, hstrerror(local_h_errno));
return 1; // error
}
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
sockaddr->sin_addr = *(struct in_addr *)hostinfo->h_addr;
// LOGf("Not using async resolver! Resolved %s to %s\n", host, inet_ntoa(sockaddr->sin_addr));
return 0;
}
#else
struct url_resolver {
char *host;
int port;
struct sockaddr_in *sockaddr;
int *status;
};
static void resolver_cleanup(void *p) {
if (p)
freeaddrinfo(p);
}
static void *resolver_thread(void *indata) {
struct url_resolver *uri = indata;
*(uri->status) = 0;
char *host = uri->host;
int port = uri->port;
struct sockaddr_in *sockaddr = uri->sockaddr;
int h_err;
struct addrinfo hints, *addrinfo = NULL;
memset(&hints, 0, sizeof hints);
int state;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &state);
pthread_cleanup_push(resolver_cleanup, NULL);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
h_err = getaddrinfo(host, NULL, &hints, &addrinfo);
pthread_cleanup_pop(0);
if (h_err == 0) {
int num_addrs = 0;
struct addrinfo *p;
for (p=addrinfo; p!=NULL; p=p->ai_next) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
sockaddr->sin_addr = ipv4->sin_addr;
char IP[INET_ADDRSTRLEN];
inet_ntop(p->ai_family, &(sockaddr->sin_addr), IP, sizeof IP);
num_addrs++;
// LOGf("Resolved[%d] %s to %s", num_addrs, host, IP);
}
freeaddrinfo(addrinfo);
*(uri->status) = 1;
} else {
*(uri->status) = 2;
}
return NULL;
}
// Returns
// 0 on success
// 1 on error
// 2 on timeout
int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
pthread_t dns_thread;
struct url_resolver uri;
int status = 0;
uri.host = host;
uri.port = port;
uri.sockaddr = sockaddr;
uri.status = &status;
int lactive = 1;
if (!active)
active = &lactive;
if (pthread_create(&dns_thread, NULL, resolver_thread, &uri)) {
log_perror("Failed to create resolver thread", errno);
return 1;
}
pthread_detach(dns_thread);
#define DNS_SLEEP 20000
long int waitcount = msec_timeout * 1000;
while (!status) {
if (!active) {
// LOG("Client !active, cancel resolver");
pthread_cancel(dns_thread);
return 2;
}
usleep(DNS_SLEEP);
waitcount = waitcount - DNS_SLEEP;
if (waitcount <= 0) {
// LOGf("Timed out resolving: %s", host);
pthread_cancel(dns_thread);
return 2; // Timed out
}
}
if (status == 1)
return 0; // Ok, resolved
return 1; // Error resolving
}
#endif