1 /* IODNSEngine_cares.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 "IODNSLookup.h"
22 #include "IOSockets.h"
30 #define _WIN32_WINNT 0x501
33 #elif defined HAVE_SYS_SELECT_H
34 #include <sys/select.h>
37 struct dnsengine_cares_socket {
38 struct _IOSocket *iosock;
43 static IOTIMER_CALLBACK(dnsengine_cares_timer_callback);
45 static ares_channel dnsengine_cares_channel;
46 static struct dnsengine_cares_socket dnsengine_cares_sockets[ARES_GETSOCK_MAXNUM];
47 static struct IOTimerDescriptor *dnsengine_cares_timer = NULL;
49 static int dnsengine_cares_init() {
52 // zero dnsengine_cares_sockets array
53 memset(dnsengine_cares_sockets, 0, sizeof(*dnsengine_cares_sockets) * ARES_GETSOCK_MAXNUM);
56 if((res = ares_init(&dnsengine_cares_channel)) != ARES_SUCCESS) {
57 iolog_trigger(IOLOG_ERROR, "Failed to initialize c-ares in %s:%d", __FILE__, __LINE__);
60 return 0; /* backend not completed */
63 static void dnsengine_cares_update_sockets() {
64 int ares_socks[ARES_GETSOCK_MAXNUM];
65 memset(ares_socks, 0, sizeof(*ares_socks) * ARES_GETSOCK_MAXNUM);
66 int sockreqs = ares_getsock(dnsengine_cares_channel, ares_socks, ARES_GETSOCK_MAXNUM);
67 int i, j, sockid, newsock, updatesock;
68 struct _IOSocket *iosock;
70 //unregister "old" sockets
71 for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
72 if(!dnsengine_cares_sockets[i].iosock)
75 //search matching ares_socks
77 for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) {
78 if(dnsengine_cares_sockets[i].iosock->fd == ares_socks[j]) {
85 _free_socket(dnsengine_cares_sockets[i].iosock);
86 dnsengine_cares_sockets[i].iosock = NULL;
90 //register new / update existing sockets
91 for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
95 //search matching dnsengine_cares_socket
97 for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) {
98 if(dnsengine_cares_sockets[j].iosock && dnsengine_cares_sockets[j].iosock->fd == ares_socks[i]) {
106 for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) {
107 if(!dnsengine_cares_sockets[j].iosock) {
113 iolog_trigger(IOLOG_ERROR, "Error in dnsengine_cares_update_sockets: could not find free dnsengine_cares_socket in %s:%d", __FILE__, __LINE__);
116 iosock = _create_socket();
121 iosock->socket_flags |= IOSOCKETFLAG_PARENT_DNSENGINE | IOSOCKETFLAG_OVERRIDE_WANT_RW;
122 iosock->fd = ares_socks[i];
123 dnsengine_cares_sockets[sockid].want_read = 0;
124 dnsengine_cares_sockets[sockid].want_write = 0;
131 if(dnsengine_cares_sockets[sockid].want_read ^ ARES_GETSOCK_READABLE(sockreqs, i)) {
132 if(ARES_GETSOCK_READABLE(sockreqs, i)) {
133 dnsengine_cares_sockets[sockid].iosock->socket_flags |= IOSOCKETFLAG_OVERRIDE_WANT_R;
134 dnsengine_cares_sockets[sockid].want_read = 1;
136 dnsengine_cares_sockets[sockid].iosock->socket_flags &= ~IOSOCKETFLAG_OVERRIDE_WANT_R;
137 dnsengine_cares_sockets[sockid].want_read = 0;
141 if(dnsengine_cares_sockets[sockid].want_write ^ ARES_GETSOCK_WRITABLE(sockreqs, i)) {
142 if(ARES_GETSOCK_WRITABLE(sockreqs, i)) {
143 dnsengine_cares_sockets[sockid].iosock->socket_flags |= IOSOCKETFLAG_OVERRIDE_WANT_W;
144 dnsengine_cares_sockets[sockid].want_write = 1;
146 dnsengine_cares_sockets[sockid].iosock->socket_flags &= ~IOSOCKETFLAG_OVERRIDE_WANT_W;
147 dnsengine_cares_sockets[sockid].want_write = 0;
151 if(updatesock || newsock) {
153 iosocket_activate(dnsengine_cares_sockets[sockid].iosock);
155 iosocket_update(dnsengine_cares_sockets[sockid].iosock);
160 static void dnsengine_cares_update_timeout() {
161 struct timeval timeout, now;
164 ares_timeout(dnsengine_cares_channel, &timeout, &timeout);
166 gettimeofday(&now, NULL);
167 timeout.tv_sec += now.tv_sec;
168 timeout.tv_usec += now.tv_usec;
169 if(timeout.tv_usec > 1000000) {
171 timeout.tv_usec -= 1000000;
174 if(dnsengine_cares_timer)
175 iotimer_set_timeout(dnsengine_cares_timer, &timeout);
177 dnsengine_cares_timer = iotimer_create(&timeout);
178 iotimer_set_callback(dnsengine_cares_timer, dnsengine_cares_timer_callback);
179 iotimer_start(dnsengine_cares_timer);
183 static IOTIMER_CALLBACK(dnsengine_cares_timer_callback) {
184 dnsengine_cares_timer = NULL;
185 ares_process_fd(dnsengine_cares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
186 dnsengine_cares_update_timeout();
187 dnsengine_cares_update_sockets();
190 static void dnsengine_cares_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite) {
191 int socketfd = iosock->fd;
192 ares_process_fd(dnsengine_cares_channel, (wantread ? socketfd : ARES_SOCKET_BAD), (wantread ? socketfd : ARES_SOCKET_BAD));
193 dnsengine_cares_update_timeout();
194 dnsengine_cares_update_sockets();
197 static void dnsengine_cares_stop() {
198 if(dnsengine_cares_timer)
199 iotimer_destroy(dnsengine_cares_timer);
204 static void dnsengine_cares_add(struct _IODNSQuery *iodns) {
208 static void dnsengine_cares_remove(struct _IODNSQuery *iodns) {
212 static void dnsengine_cares_loop() {
216 struct IODNSEngine dnsengine_cares = {
218 .init = dnsengine_cares_init,
219 .stop = dnsengine_cares_stop,
220 .add = dnsengine_cares_add,
221 .remove = dnsengine_cares_remove,
222 .loop = dnsengine_cares_loop,
223 .socket_callback = dnsengine_cares_socket_callback,
228 struct IODNSEngine dnsengine_cares = {
235 .socket_callback = NULL,