[IOMultiplexerV2] fixed some WIN32 compilation issues
[NextIRCd.git] / src / IOHandler / IODNSLookup.c
1 /* IODNSLookup.c - IOMultiplexer
2  * Copyright (C) 2014  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  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License 
16  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
17  */
18 #define _IOHandler_internals
19 #include "IOInternal.h"
20 #include "IOHandler.h"
21 #include "IODNSLookup.h"
22 #include "IOLog.h"
23 #include "IOSockets.h"
24
25 #ifdef WIN32
26 #ifdef _WIN32_WINNT
27 #undef _WIN32_WINNT
28 #endif
29 #define _WIN32_WINNT 0x501
30 #include <winsock2.h>
31 #include <windows.h>
32 #include <ws2tcpip.h>
33 #else
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <netinet/ip.h> 
37 #include <arpa/inet.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #endif
41 #include "compat/inet.h"
42
43 #include <string.h>
44
45 struct _IODNSQuery *iodnsquery_first = NULL;
46 struct _IODNSQuery *iodnsquery_last = NULL;
47
48 struct IODNSEngine *dnsengine = NULL;
49
50 static void iodns_init_engine() {
51         if(dnsengine)
52                 return;
53         //try DNS engines
54         if(dnsengine_cares.init && dnsengine_cares.init())
55                 dnsengine = &dnsengine_cares;
56         else if(dnsengine_default.init && dnsengine_default.init())
57                 dnsengine = &dnsengine_default;
58         else {
59                 iolog_trigger(IOLOG_FATAL, "found no useable IO DNS engine");
60                 return;
61         }
62         iolog_trigger(IOLOG_DEBUG, "using %s IODNS engine", dnsengine->name);
63 }
64
65 void _init_iodns() {
66         iodns_init_engine();
67 }
68
69 struct _IODNSQuery *_create_dnsquery() {
70         struct _IODNSQuery *query = calloc(1, sizeof(*query));
71         if(!query) {
72                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IODNSQuery in %s:%d", __FILE__, __LINE__);
73                 return NULL;
74         }
75         if(iodnsquery_last)
76                 iodnsquery_last->next = query;
77         else
78                 iodnsquery_first = query;
79         query->prev = iodnsquery_last;
80         iodnsquery_last = query;
81         return query;
82 }
83
84 void _start_dnsquery(struct _IODNSQuery *query) {
85         query->flags |= IODNSFLAG_RUNNING;
86         dnsengine->add(query);
87 }
88
89 void _free_dnsquery(struct _IODNSQuery *query) {
90         if(query->prev)
91                 query->prev->next = query->next;
92         else
93                 iodnsquery_first = query->next;
94         if(query->next)
95                 query->next->prev = query->prev;
96         else
97                 iodnsquery_last = query->prev;
98         if((query->type & IODNS_REVERSE) && query->request.addr.address)
99                 free(query->request.addr.address);
100         free(query);
101 }
102
103 void _stop_dnsquery(struct _IODNSQuery *query) {
104         if((query->flags & IODNSFLAG_RUNNING)) {
105                 query->flags &= ~IODNSFLAG_RUNNING;
106                 dnsengine->remove(query);
107         }
108         if(!(query->flags & IODNSFLAG_PROCESSING))
109                 _free_dnsquery(query);
110 }
111
112 void iodns_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite) {
113         if(dnsengine && dnsengine->socket_callback)
114                 dnsengine->socket_callback(iosock, wantread, wantwrite);
115 }
116
117 void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state) {
118         if((query->flags & IODNSFLAG_PARENT_PUBLIC)) {
119                 struct IODNSQuery *descriptor = query->parent;
120                 struct IODNSEvent event;
121                 event.type = state;
122                 event.query = descriptor;
123                 event.result = query->result;
124                 
125                 descriptor->query = NULL;
126                 _stop_dnsquery(query);
127                 
128                 if(descriptor->callback)
129                         descriptor->callback(&event);
130                 
131                 iogc_add(descriptor);
132         } else if((query->flags & IODNSFLAG_PARENT_SOCKET)) {
133                 struct IODNSEvent event;
134                 event.type = state;
135                 event.query = NULL;
136                 event.result = query->result;
137                 void *parent = query->parent;
138                 
139                 _stop_dnsquery(query);
140                 iosocket_lookup_callback(parent, &event);
141                 
142         }
143 }
144
145 void iodns_poll() {
146         if(dnsengine)
147                 dnsengine->loop();
148 }
149
150 /* public functions */
151
152 struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback, void *arg) {
153         if(!(records & IODNS_FORWARD) || !hostname || !callback)
154                 return NULL;
155         
156         struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
157         if(!descriptor) {
158                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
159                 return NULL;
160         }
161         
162         struct _IODNSQuery *query = _create_dnsquery();
163         if(!query) {
164                 free(descriptor);
165                 return NULL;
166         }
167         
168         query->parent = descriptor;
169         query->flags |= IODNSFLAG_PARENT_PUBLIC;
170         descriptor->query = query;
171         descriptor->data = arg;
172         
173         query->request.host = strdup(hostname);
174         query->type = (records & IODNS_FORWARD);
175         
176         descriptor->callback = callback;
177         
178         _start_dnsquery(query);
179         return descriptor;
180 }
181
182 struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, size_t addrlen, iodns_callback *callback, void *arg) {
183         if(!addr || !callback)
184                 return NULL;
185         
186         struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
187         if(!descriptor) {
188                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
189                 return NULL;
190         }
191         
192         struct _IODNSQuery *query = _create_dnsquery();
193         if(!query) {
194                 free(descriptor);
195                 return NULL;
196         }
197         
198         query->parent = descriptor;
199         query->flags |= IODNSFLAG_PARENT_PUBLIC;
200         descriptor->query = query;
201         descriptor->data = arg;
202         
203         query->type = IODNS_RECORD_PTR;
204         query->request.addr.addresslen = addrlen;
205         query->request.addr.address = malloc(addrlen);
206         if(!query->request.addr.address) {
207                 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
208                 _free_dnsquery(query);
209                 free(descriptor);
210                 return NULL;
211         }
212         memcpy(query->request.addr.address, addr, addrlen);
213         
214         descriptor->callback = callback;
215         
216         _start_dnsquery(query);
217         return descriptor;
218 }
219
220 void iodns_abort(struct IODNSQuery *descriptor) {
221         if(!descriptor)
222                 return;
223         
224         struct _IODNSQuery *query = descriptor->query;
225         if(!query) {
226                 iolog_trigger(IOLOG_WARNING, "called iodns_abort for destroyed IODNSQuery in %s:%d", __FILE__, __LINE__);
227                 return;
228         }
229         
230         _stop_dnsquery(query);
231 }
232
233 int iodns_print_address(struct IODNSAddress *address, int ipv6, char *buffer, int length) {
234         int af;
235         void *addr;
236         if(ipv6) {
237                 af = AF_INET6;
238                 addr = (void *)(&((struct sockaddr_in6 *)address->address)->sin6_addr);
239         } else {
240                 af = AF_INET;
241                 addr = (void *)(&((struct sockaddr_in *)address->address)->sin_addr);
242         }
243         buffer = (char*) inet_ntop(af, addr, buffer, length);
244         if(!buffer)
245                 return 0;
246         else
247                 return strlen(buffer);
248 }
249
250 void iodns_free_result(struct IODNSResult *result) {
251         struct IODNSResult *next;
252         for(;result;result = next) {
253                 next = result->next;
254                 
255                 if((result->type & IODNS_FORWARD)) {
256                         if(result->result.addr.address)
257                                 free(result->result.addr.address);
258                 }
259                 if((result->type & IODNS_REVERSE)) {
260                         if(result->result.host)
261                                 free(result->result.host);
262                 }
263                 free(result);
264         }
265 }
266