+/* IODNSHandler.c - IOMultiplexer
+ * Copyright (C) 2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "IODNSHandler.h"
+#include "IODNSEngine.h"
+
+struct IODNSQuery *first_dnsquery = NULL;
+struct IODNSQuery *last_dnsquery = NULL;
+int dnsquery_count = 0;
+
+extern struct IODNSEngine dnsengine_cares;
+extern struct IODNSEngine dnsengine_default;
+
+struct IODNSEngine *dnsengine = NULL;
+
+static void iodns_init_engine() {
+ if(dnsengine)
+ return;
+ //try DNS engines
+ if(dnsengine_cares.init && dnsengine_cares.init())
+ dnsengine = &dnsengine_cares;
+ else if(dnsengine_default.init && dnsengine_default.init())
+ dnsengine = &dnsengine_default;
+ else {
+ iohandler_log(IOLOG_FATAL, "found no useable IO DNS engine");
+ return;
+ }
+}
+
+static void iodns_append(struct IODNSQuery *query) {
+ IOSYNCHRONIZE(io_thread_sync);
+ query->next = NULL;
+ query->prev = last_dnsquery;
+ last_dnsquery = query;
+ if(!first_dnsquery)
+ first_dnsquery = query;
+ dnsquery_count++;
+ IODESYNCHRONIZE(io_thread_sync);
+}
+
+static void iodns_remove(struct IODNSQuery *query) {
+ IOSYNCHRONIZE(io_thread_sync);
+ if(query->next)
+ query->next->prev = query->prev;
+ else
+ last_dnsquery = query->prev;
+ if(query->prev)
+ query->prev->next = query->next;
+ else
+ first_dnsquery = query->next;
+ dnsquery_count--;
+ IODESYNCHRONIZE(io_thread_sync);
+}
+
+static void iodns_free(struct IODNSQuery *query) {
+ if(query->hostname)
+ free(query->hostname);
+ if((query->type & IODNS_REVERSE) && query->address.addr)
+ free(query->addr.address);
+ free(query);
+}
+
+struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback) {
+ if(!dnsengine)
+ iodns_init_engine();
+ if(!(records & IODNS_FORWARD) || !hostname || !callback)
+ return NULL;
+ struct IODNSQuery *query = calloc(1, sizeof(*query));
+ query->hostname = strdup(hostname);
+ query->type = (records & IODNS_FORWARD);
+ query->callback = callback;
+ iodns_append(query);
+ dnsengine->add(query);
+ return query;
+}
+
+struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, iodns_callback *callback) {
+ if(!dnsengine)
+ iodns_init_engine();
+ if(!addr || !callback)
+ return NULL;
+ struct IODNSQuery *query = calloc(1, sizeof(*query));
+ query->address = malloc(addrlen);
+ memcpy(query->addr.address, addr, addrlen);
+ query->addresslen = addrlen;
+ query->type = IODNS_RECORD_PTR;
+ query->callback = callback;
+ iodns_append(query);
+ dnsengine->add(query);
+ return query;
+}
+
+void iodns_abort(struct IODNSQuery *query) {
+ if(!dnsengine || !query)
+ return;
+ dnsengine->remove(query);
+ iodns_remove(query);
+ iodns_free(query);
+}
+
+void iodns_event_callback(struct IODNSQuery *iodns, enum IODNSEventType state) {
+ struct IODNSEvent event;
+ event.type = state;
+ event.query = iodns;
+ dnsengine->remove(iodns);
+ iodns_remove(iodns);
+ if(iodns->callback)
+ iodns->callback(event);
+ iodns_free(iodns);
+}
+
+void iodns_poll() {
+ if(dnsengine)
+ dnsengine.loop();
+}
+
+void iodns_free_result(struct IODNSResult *result) {
+ struct IODNSResult *next;
+ for(;result;result = next) {
+ next = result->next;
+ free(result->address);
+ free(result);
+ }
+}
+