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>
32 #include <arpa/inet.h>
34 #include "compat/inet.h"
39 #ifdef IODNS_USE_THREADS
40 static pthread_t iodns_thread;
41 static int iodns_thread_running = 1;
43 static pthread_cond_t iodns_cond;
44 static pthread_mutex_t iodns_sync, iodns_sync2;
46 static int iodns_loop_blocking = 0;
48 static void iodns_process_queries();
50 #ifdef IODNS_USE_THREADS
51 static void *dnsengine_worker_main(void *arg) {
52 struct _IODNSQuery *query;
53 while(iodns_thread_running) {
54 IOSYNCHRONIZE(iodns_sync);
55 for(query = iodnsquery_first; query; query = query->next) {
56 if((query->flags & IODNSFLAG_RUNNING))
59 IODESYNCHRONIZE(iodns_sync);
61 pthread_cond_wait(&iodns_cond, &iodns_sync2);
63 if(iodns_thread_running)
64 iodns_process_queries();
70 static int dnsengine_default_init() {
71 #ifdef IODNS_USE_THREADS
72 /* create worker thread */
73 pthread_cond_init(&iodns_cond, NULL);
74 IOTHREAD_MUTEX_INIT(iodns_sync);
75 IOTHREAD_MUTEX_INIT(iodns_sync2);
77 iodns_thread_running = 1;
80 thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
82 iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
83 iodns_loop_blocking = 1;
84 iodns_thread_running = 0;
87 iodns_loop_blocking = 1;
92 static void dnsengine_default_stop() {
93 #ifdef IODNS_USE_THREADS
94 if(iodns_thread_running) {
95 iodns_thread_running = 0;
96 IOSYNCHRONIZE(iodns_sync2);
97 pthread_cond_signal(&iodns_cond);
98 IODESYNCHRONIZE(iodns_sync2);
99 pthread_join(iodns_thread, NULL);
104 static void dnsengine_default_add(struct _IODNSQuery *iodns) {
105 #ifdef IODNS_USE_THREADS
106 if(iodns_thread_running) {
107 IOSYNCHRONIZE(iodns_sync2);
108 pthread_cond_signal(&iodns_cond);
109 IODESYNCHRONIZE(iodns_sync2);
114 static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
118 static void dnsengine_default_loop() {
119 if(iodns_loop_blocking)
120 iodns_process_queries();
123 static void iodns_process_queries() {
124 enum IODNSEventType querystate;
125 struct addrinfo hints, *res, *allres;
126 struct _IODNSQuery *iodns, *next_iodns;
127 struct IODNSResult *dnsresult;
128 iodns_process_queries_start:
129 IOSYNCHRONIZE(iodns_sync);
130 for(iodns = iodnsquery_first; iodns; iodns = next_iodns) {
131 next_iodns = iodns->next;
133 if(!(iodns->flags & IODNSFLAG_RUNNING))
135 if((iodns->flags & IODNSFLAG_PROCESSING))
138 IODESYNCHRONIZE(iodns_sync);
140 querystate = IODNSEVENT_FAILED;
142 if((iodns->type & IODNS_FORWARD)) {
143 memset (&hints, 0, sizeof (hints));
144 hints.ai_family = PF_UNSPEC;
145 hints.ai_socktype = SOCK_STREAM;
146 hints.ai_flags |= AI_CANONNAME;
148 if (!(ret = getaddrinfo(iodns->request.host, NULL, &hints, &allres))) {
151 switch (res->ai_family) {
153 if((iodns->type & IODNS_RECORD_A)) {
154 dnsresult = malloc(sizeof(*dnsresult));
155 dnsresult->type = IODNS_RECORD_A;
156 dnsresult->result.addr.addresslen = res->ai_addrlen;
157 dnsresult->result.addr.address = malloc(dnsresult->result.addr.addresslen);
158 memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
159 dnsresult->next = iodns->result;
160 iodns->result = dnsresult;
162 char str[INET_ADDRSTRLEN];
163 inet_ntop( AF_INET, &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr, str, INET_ADDRSTRLEN );
164 iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
166 querystate = IODNSEVENT_SUCCESS;
170 if((iodns->type & IODNS_RECORD_AAAA)) {
171 dnsresult = malloc(sizeof(*dnsresult));
172 dnsresult->type = IODNS_RECORD_AAAA;
173 dnsresult->result.addr.addresslen = res->ai_addrlen;
174 dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
175 memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
176 dnsresult->next = iodns->result;
177 iodns->result = dnsresult;
179 char str[INET6_ADDRSTRLEN];
180 inet_ntop( AF_INET6, &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN );
181 iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
183 querystate = IODNSEVENT_SUCCESS;
189 freeaddrinfo(allres);
191 iolog_trigger(IOLOG_WARNING, "getaddrinfo returned error code: %d", ret);
194 IOSYNCHRONIZE(iodns_sync);
195 if(!(iodns->flags & IODNSFLAG_RUNNING)) {
196 iodns_free_result(iodns->result);
197 _free_dnsquery(iodns);
198 IODESYNCHRONIZE(iodns_sync);
199 goto iodns_process_queries_start;
201 iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
202 IODESYNCHRONIZE(iodns_sync);
203 iodns_event_callback(iodns, querystate);
204 goto iodns_process_queries_start;
208 struct IODNSEngine dnsengine_default = {
210 .init = dnsengine_default_init,
211 .stop = dnsengine_default_stop,
212 .add = dnsengine_default_add,
213 .remove = dnsengine_default_remove,
214 .loop = dnsengine_default_loop,