1 /* IODNSEngine_default.c - IOMultiplexer
2 * Copyright (C) 2014 Philipp Kreil (pk910)
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.
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.
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/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
21 #include "IODNSLookup.h"
24 #define _WIN32_WINNT 0x501
29 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include "compat/inet.h"
38 #ifdef IODNS_USE_THREADS
39 static pthread_t iodns_thread;
40 static int iodns_thread_running = 1;
42 static pthread_cond_t iodns_cond;
43 static pthread_mutex_t iodns_sync, iodns_sync2;
45 static int iodns_loop_blocking = 0;
47 static void iodns_process_queries();
49 #ifdef IODNS_USE_THREADS
50 static void *dnsengine_worker_main(void *arg) {
51 struct _IODNSQuery *query;
52 while(iodns_thread_running) {
53 IOSYNCHRONIZE(iodns_sync);
54 for(query = iodnsquery_first; query; query = query->next) {
55 if((query->flags & IODNSFLAG_RUNNING))
58 IODESYNCHRONIZE(iodns_sync);
60 pthread_cond_wait(&iodns_cond, &iodns_sync2);
62 if(iodns_thread_running)
63 iodns_process_queries();
69 static int dnsengine_default_init() {
70 #ifdef IODNS_USE_THREADS
71 /* create worker thread */
72 pthread_cond_init(&iodns_cond, NULL);
73 IOTHREAD_MUTEX_INIT(iodns_sync);
74 IOTHREAD_MUTEX_INIT(iodns_sync2);
76 iodns_thread_running = 1;
79 thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
81 iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
82 iodns_loop_blocking = 1;
83 iodns_thread_running = 0;
86 iodns_loop_blocking = 1;
91 static void dnsengine_default_stop() {
92 #ifdef IODNS_USE_THREADS
93 if(iodns_thread_running) {
94 iodns_thread_running = 0;
95 IOSYNCHRONIZE(iodns_sync2);
96 pthread_cond_signal(&iodns_cond);
97 IODESYNCHRONIZE(iodns_sync2);
98 pthread_join(iodns_thread, NULL);
103 static void dnsengine_default_add(struct _IODNSQuery *iodns) {
104 #ifdef IODNS_USE_THREADS
105 if(iodns_thread_running) {
106 IOSYNCHRONIZE(iodns_sync2);
107 pthread_cond_signal(&iodns_cond);
108 IODESYNCHRONIZE(iodns_sync2);
113 static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
117 static void dnsengine_default_loop() {
118 if(iodns_loop_blocking)
119 iodns_process_queries();
122 static void iodns_process_queries() {
123 enum IODNSEventType querystate;
124 struct addrinfo hints, *res, *allres;
125 struct _IODNSQuery *iodns, *next_iodns;
126 struct IODNSResult *dnsresult;
127 iodns_process_queries_start:
128 IOSYNCHRONIZE(iodns_sync);
129 for(iodns = iodnsquery_first; iodns; iodns = next_iodns) {
130 next_iodns = iodns->next;
132 if(!(iodns->flags & IODNSFLAG_RUNNING))
134 if((iodns->flags & IODNSFLAG_PROCESSING))
137 IODESYNCHRONIZE(iodns_sync);
139 querystate = IODNSEVENT_FAILED;
141 if((iodns->type & IODNS_FORWARD)) {
142 memset (&hints, 0, sizeof (hints));
143 hints.ai_family = PF_UNSPEC;
144 hints.ai_socktype = SOCK_STREAM;
145 hints.ai_flags |= AI_CANONNAME;
147 if (!(ret = getaddrinfo(iodns->request.host, NULL, &hints, &allres))) {
150 switch (res->ai_family) {
152 if((iodns->type & IODNS_RECORD_A)) {
153 dnsresult = malloc(sizeof(*dnsresult));
154 dnsresult->type = IODNS_RECORD_A;
155 dnsresult->result.addr.addresslen = res->ai_addrlen;
156 dnsresult->result.addr.address = malloc(dnsresult->result.addr.addresslen);
157 memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
158 dnsresult->next = iodns->result;
159 iodns->result = dnsresult;
161 char str[INET_ADDRSTRLEN];
162 inet_ntop( AF_INET, &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr, str, INET_ADDRSTRLEN );
163 iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
165 querystate = IODNSEVENT_SUCCESS;
169 if((iodns->type & IODNS_RECORD_AAAA)) {
170 dnsresult = malloc(sizeof(*dnsresult));
171 dnsresult->type = IODNS_RECORD_AAAA;
172 dnsresult->result.addr.addresslen = res->ai_addrlen;
173 dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
174 memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
175 dnsresult->next = iodns->result;
176 iodns->result = dnsresult;
178 char str[INET6_ADDRSTRLEN];
179 inet_ntop( AF_INET6, &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN );
180 iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
182 querystate = IODNSEVENT_SUCCESS;
188 freeaddrinfo(allres);
190 iolog_trigger(IOLOG_WARNING, "getaddrinfo returned error code: %d", ret);
193 IOSYNCHRONIZE(iodns_sync);
194 if(!(iodns->flags & IODNSFLAG_RUNNING)) {
195 iodns_free_result(iodns->result);
196 _free_dnsquery(iodns);
197 IODESYNCHRONIZE(iodns_sync);
198 goto iodns_process_queries_start;
200 iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
201 IODESYNCHRONIZE(iodns_sync);
202 iodns_event_callback(iodns, querystate);
203 goto iodns_process_queries_start;
207 struct IODNSEngine dnsengine_default = {
209 .init = dnsengine_default_init,
210 .stop = dnsengine_default_stop,
211 .add = dnsengine_default_add,
212 .remove = dnsengine_default_remove,
213 .loop = dnsengine_default_loop,