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"
20 #include "IODNSHandler.h"
23 static pthread_t *iodns_thread;
24 static int iodns_thread_running = 1;
26 static pthread_cond_t iodns_cond;
27 static pthread_mutex_t iodns_sync2;
29 static int iodns_loop_blocking = 0;
31 static void iodns_process_queries();
33 static void dnsengine_worker_main(void *arg) {
34 struct _IODNSQuery *query;
35 while(iodns_thread_running) {
36 IOSYNCHRONIZE(iodns_sync);
37 for(query = iodnsquery_first; query; query = query->next) {
38 if((query->flags & IODNSFLAG_RUNNING))
41 IODESYNCHRONIZE(iodns_sync);
43 pthread_cond_wait(&iodns_cond, &iodns_sync2);
45 if(iodns_thread_running)
46 iodns_process_queries();
50 static int dnsengine_default_init() {
52 /* create worker thread */
53 pthread_cond_init(&iodns_cond, NULL);
54 IOTHREAD_MUTEX_INIT(iodns_sync2);
56 iodns_thread_running = 1;
59 thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
61 iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
62 iodns_loop_blocking = 1;
64 iodns_thread_running = 0;
67 iodns_loop_blocking = 1;
72 static void dnsengine_default_stop() {
74 if(iodns_thread_running) {
75 iodns_thread_running = 0;
76 IOSYNCHRONIZE(iodns_sync2);
77 pthread_cond_signal(&iodns_cond);
78 IODESYNCHRONIZE(iodns_sync2);
79 pthread_join(iodns_thread, NULL);
84 static void dnsengine_default_add(struct _IODNSQuery *iodns) {
86 if(iodns_thread_running) {
87 IOSYNCHRONIZE(iodns_sync2);
88 pthread_cond_signal(&iodns_cond);
89 IODESYNCHRONIZE(iodns_sync2);
94 static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
98 static void dnsengine_default_loop() {
99 if(iodns_loop_blocking)
100 iodns_process_queries();
103 static void iodns_process_queries() {
104 enum IODNSEventType querystate;
105 struct addrinfo hints, *res, *next_res;
106 struct _IODNSQuery *iodns, *next_iodns;
107 struct IODNSResult *dnsresult;
108 iodns_process_queries_start:
109 IOSYNCHRONIZE(iodns_sync);
110 for(iodns = first_dnsquery; iodns; iodns = next_iodns) {
111 next_iodns = iodns->next;
113 if(!(iodns->flags & IODNSFLAG_RUNNING))
115 if((iodns->flags & IODNSFLAG_PROCESSING))
118 IODESYNCHRONIZE(iodns_sync);
120 querystate = IODNSEVENT_FAILED;
122 if((iodns->type & IODNS_FORWARD)) {
123 memset (&hints, 0, sizeof (hints));
124 hints.ai_family = PF_UNSPEC;
125 hints.ai_socktype = SOCK_STREAM;
126 hints.ai_flags |= AI_CANONNAME;
127 if (!getaddrinfo(iodns->request.host, NULL, &hints, &res)) {
129 switch (res->ai_family) {
131 if((iodns->type & IODNS_RECORD_A)) {
132 dnsresult = malloc(sizeof(*dnsresult));
133 dnsresult->type = IODNS_RECORD_A;
134 dnsresult->result.addr.addresslen = res->ai_addrlen;
135 dnsresult->result.addr.address = malloc(dnsresult->addresslen);
136 memcpy(dnsresult->address, res->ai_addr, dnsresult->addresslen);
137 dnsresult->next = iodns->result;
138 iodns->result = dnsresult;
139 querystate = IODNSEVENT_SUCCESS;
143 if((iodns->type & IODNS_RECORD_AAAA)) {
144 dnsresult = malloc(sizeof(*dnsresult));
145 dnsresult->type = IODNS_RECORD_AAAA;
146 dnsresult->result.addr.addresslen = res->ai_addrlen;
147 dnsresult->result.addr.address = malloc(dnsresult->addresslen);
148 memcpy(dnsresult->address, res->ai_addr, dnsresult->addresslen);
149 dnsresult->next = iodns->result;
150 iodns->result = dnsresult;
151 querystate = IODNSEVENT_SUCCESS;
155 next_res = res->ai_next;
161 IOSYNCHRONIZE(iodns_sync);
162 if(!(iodns->flags & IODNSFLAG_RUNNING)) {
163 iodns_free_result(iodns->result);
164 _free_dnsquery(iodns);
165 IODESYNCHRONIZE(iodns_sync);
166 goto iodns_process_queries_start;
168 iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
169 IODESYNCHRONIZE(iodns_sync);
170 iodns_event_callback(iodns, querystate);
171 goto iodns_process_queries_start;
175 struct IODNSEngine dnsengine_default = {
177 .init = dnsengine_default_init,
178 .stop = dnsengine_default_stop,
179 .add = dnsengine_default_add,
180 .remove = dnsengine_default_remove,
181 .loop = dnsengine_default_loop,