[IOMultiplexer] Added asynchronous DNS Lookups
[IOMultiplexer.git] / src / IODNSHandler.c
1 /* IODNSHandler.c - IOMultiplexer
2  * Copyright (C) 2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "IODNSHandler.h"
18 #include "IODNSEngine.h"
19
20 struct IODNSQuery *first_dnsquery = NULL;
21 struct IODNSQuery *last_dnsquery = NULL;
22 int dnsquery_count = 0;
23
24 extern struct IODNSEngine dnsengine_cares;
25 extern struct IODNSEngine dnsengine_default;
26
27 struct IODNSEngine *dnsengine = NULL;
28
29 static void iodns_init_engine() {
30     if(dnsengine)
31         return;
32     //try DNS engines
33     if(dnsengine_cares.init && dnsengine_cares.init())
34         dnsengine = &dnsengine_cares;
35     else if(dnsengine_default.init && dnsengine_default.init())
36         dnsengine = &dnsengine_default;
37     else {
38         iohandler_log(IOLOG_FATAL, "found no useable IO DNS engine");
39         return;
40     }
41 }
42
43 static void iodns_append(struct IODNSQuery *query) {
44     IOSYNCHRONIZE(io_thread_sync);
45     query->next = NULL;
46     query->prev = last_dnsquery;
47     last_dnsquery = query;
48     if(!first_dnsquery)
49         first_dnsquery = query;
50     dnsquery_count++;
51     IODESYNCHRONIZE(io_thread_sync);
52 }
53
54 static void iodns_remove(struct IODNSQuery *query) {
55     IOSYNCHRONIZE(io_thread_sync);
56     if(query->next)
57         query->next->prev = query->prev;
58     else
59         last_dnsquery = query->prev;
60     if(query->prev)
61         query->prev->next = query->next;
62     else
63         first_dnsquery = query->next;
64     dnsquery_count--;
65     IODESYNCHRONIZE(io_thread_sync);
66 }
67
68 static void iodns_free(struct IODNSQuery *query) {
69     if(query->hostname)
70         free(query->hostname);
71     if((query->type & IODNS_REVERSE) && query->address.addr)
72         free(query->addr.address);
73     free(query);
74 }
75
76 struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback) {
77     if(!dnsengine)
78         iodns_init_engine();
79     if(!(records & IODNS_FORWARD) || !hostname || !callback)
80         return NULL;
81     struct IODNSQuery *query = calloc(1, sizeof(*query));
82     query->hostname = strdup(hostname);
83     query->type = (records & IODNS_FORWARD);
84     query->callback = callback;
85     iodns_append(query);
86     dnsengine->add(query);
87     return query;
88 }
89
90 struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, iodns_callback *callback) {
91     if(!dnsengine)
92         iodns_init_engine();
93     if(!addr || !callback)
94         return NULL;
95     struct IODNSQuery *query = calloc(1, sizeof(*query));
96     query->address = malloc(addrlen);
97     memcpy(query->addr.address, addr, addrlen);
98     query->addresslen = addrlen;
99     query->type = IODNS_RECORD_PTR;
100     query->callback = callback;
101     iodns_append(query);
102     dnsengine->add(query);
103     return query;
104 }
105
106 void iodns_abort(struct IODNSQuery *query) {
107     if(!dnsengine || !query)
108         return;
109     dnsengine->remove(query);
110     iodns_remove(query);
111     iodns_free(query);
112 }
113
114 void iodns_event_callback(struct IODNSQuery *iodns, enum IODNSEventType state) {
115     struct IODNSEvent event;
116     event.type = state;
117     event.query = iodns;
118     dnsengine->remove(iodns);
119     iodns_remove(iodns);
120     if(iodns->callback)
121         iodns->callback(event);
122     iodns_free(iodns);
123 }
124
125 void iodns_poll() {
126     if(dnsengine)
127         dnsengine.loop();
128 }
129
130 void iodns_free_result(struct IODNSResult *result) {
131     struct IODNSResult *next;
132     for(;result;result = next) {
133         next = result->next;
134         free(result->address);
135         free(result);
136     }
137 }
138