[IOMultiplexer] Added asynchronous DNS Lookups
[IOMultiplexer.git] / src / IODNSHandler.c
diff --git a/src/IODNSHandler.c b/src/IODNSHandler.c
new file mode 100644 (file)
index 0000000..1caebdd
--- /dev/null
@@ -0,0 +1,138 @@
+/* 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);
+    }
+}
+