]> code.citadel.org Git - citadel.git/blobdiff - citadel/modules/c-ares-dns/serv_c-ares-dns.c
Add busines logic for toggling multiple mx records etc.
[citadel.git] / citadel / modules / c-ares-dns / serv_c-ares-dns.c
index adb0827f35cab7bcea4206442f25f87d74f2bb06..cba9d8303e52c4236ea69b1074fe9540db5892a0 100644 (file)
@@ -59,8 +59,6 @@
 
 
 extern struct ev_loop *event_base;
-struct ares_options options;
-ares_channel Channel;
 
 void SockStateCb(void *data, int sock, int read, int write);
 
@@ -71,12 +69,12 @@ static void HostByAddrCb(void *data,
                          struct hostent *hostent) 
 {
        AsyncIO *IO = data;
-       IO->DNSStatus = status;
+       IO->DNSQuery->DNSStatus = status;
        if  (status != ARES_SUCCESS) {
 //             ResolveError(*cb, status);
                return;
        }
-       IO->Data = hostent;
+       IO->DNSQuery->Data = hostent;
 /// TODO: howto free this??
 }
 
@@ -84,17 +82,17 @@ static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct hostent* host;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
-       IO->VParsedDNSReply = host;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
+       IO->DNSQuery->VParsedDNSReply = host;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
 }
 
 
@@ -102,17 +100,17 @@ static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct hostent* host;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
-       IO->VParsedDNSReply = host;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
+       IO->DNSQuery->VParsedDNSReply = host;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
 }
 
 
@@ -120,19 +118,19 @@ static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct hostent* host;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
 
        // a CNAME lookup always returns a single record but
-       IO->VParsedDNSReply = host;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
+       IO->DNSQuery->VParsedDNSReply = host;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
 }
 
 
@@ -140,18 +138,18 @@ static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct ares_mx_reply *mx_out;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
 
-       IO->VParsedDNSReply = mx_out;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_data;
+       IO->DNSQuery->VParsedDNSReply = mx_out;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_data;
 }
 
 
@@ -159,17 +157,17 @@ static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct hostent* host;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_ns_reply(abuf, alen, &host);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_ns_reply(abuf, alen, &host);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
-       IO->VParsedDNSReply = host;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
+       IO->DNSQuery->VParsedDNSReply = host;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
 }
 
 
@@ -177,18 +175,18 @@ static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct ares_srv_reply *srv_out;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
 
-       IO->VParsedDNSReply = srv_out;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_data;
+       IO->DNSQuery->VParsedDNSReply = srv_out;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_data;
 }
 
 
@@ -196,17 +194,17 @@ static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen)
 {
        struct ares_txt_reply *txt_out;
 
-       if (IO->VParsedDNSReply != NULL)
-               IO->DNSReplyFree(IO->VParsedDNSReply);
-       IO->VParsedDNSReply = NULL;
+       if (IO->DNSQuery->VParsedDNSReply != NULL)
+               IO->DNSQuery->DNSReplyFree(IO->DNSQuery->VParsedDNSReply);
+       IO->DNSQuery->VParsedDNSReply = NULL;
 
-       IO->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out);
-       if (IO->DNSStatus != ARES_SUCCESS) {
+       IO->DNSQuery->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out);
+       if (IO->DNSQuery->DNSStatus != ARES_SUCCESS) {
 //    ResolveError(arg->js_cb, status);
                return;
        }
-       IO->VParsedDNSReply = txt_out;
-       IO->DNSReplyFree = (FreeDNSReply) ares_free_data;
+       IO->DNSQuery->VParsedDNSReply = txt_out;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_data;
 }
 
 void QueryCb(void *arg,
@@ -217,55 +215,106 @@ void QueryCb(void *arg,
 {
        AsyncIO *IO = arg;
 
-       IO->DNSStatus = status;
+       IO->DNSQuery->DNSStatus = status;
        if (status == ARES_SUCCESS)
-               IO->DNS_CB(arg, abuf, alen);
-       ev_io_stop(event_base, &IO->dns_io_event);
-               
-       IO->PostDNS(IO);
+               IO->DNSQuery->DNS_CB(arg, abuf, alen);
+       else
+               IO->DNSQuery->DNSStatus = status;
+///    ev_io_stop(event_base, &IO->DNSQuery->dns_io_event);
+       
+       ev_idle_init(&IO->unwind_stack,
+                    IO_postdns_callback);
+       IO->unwind_stack.data = IO;
+       ev_idle_start(event_base, &IO->unwind_stack);
+       CtdlLogPrintf(CTDL_DEBUG, "C-ARES: %s\n", __FUNCTION__);
 }
 
-int QueueQuery(ns_type Type, char *name, AsyncIO *IO, IO_CallBack PostDNS)
+void QueryCbDone(AsyncIO *IO)
 {
-       int length, family;
-       char address_b[sizeof(struct in6_addr)];
-       int optmask = 0;
+       ev_idle_stop(event_base, &IO->unwind_stack);
+}
 
+
+void InitC_ares_dns(AsyncIO *IO)
+{
+       int optmask = 0;
        if (IO->DNSChannel == NULL) {
                optmask |= ARES_OPT_SOCK_STATE_CB;
                IO->DNSOptions.sock_state_cb = SockStateCb;
                IO->DNSOptions.sock_state_cb_data = IO;
                ares_init_options(&IO->DNSChannel, &IO->DNSOptions, optmask);
        }
+}
+
+void QueueGetHostByNameDone(void *Ctx, 
+                           int status,
+                           int timeouts,
+                           struct hostent *hostent)
+{
+       AsyncIO *IO = (AsyncIO *) Ctx;
+
+       IO->DNSQuery->DNSStatus = status;
+       IO->DNSQuery->VParsedDNSReply = hostent;
+       IO->DNSQuery->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
+
+       ev_idle_init(&IO->unwind_stack,
+                    IO_postdns_callback);
+       IO->unwind_stack.data = IO;
+       ev_idle_start(event_base, &IO->unwind_stack);
+       CtdlLogPrintf(CTDL_DEBUG, "C-ARES: %s\n", __FUNCTION__);
+}
+
+void QueueGetHostByName(AsyncIO *IO, const char *Hostname, DNSQueryParts *QueryParts, IO_CallBack PostDNS)
+{
+       IO->DNSQuery = QueryParts;
+       IO->DNSQuery->PostDNS = PostDNS;
+
+       InitC_ares_dns(IO);
+
+       ares_gethostbyname(IO->DNSChannel,
+                          Hostname,   
+                          AF_INET6, /* it falls back to ipv4 in doubt... */
+                          QueueGetHostByNameDone,
+                          IO);
+//get_one_mx_host_ip_done);
+}
+int QueueQuery(ns_type Type, const char *name, AsyncIO *IO, DNSQueryParts *QueryParts, IO_CallBack PostDNS)
+{
+       int length, family;
+       char address_b[sizeof(struct in6_addr)];
+
+       IO->DNSQuery = QueryParts;
+       IO->DNSQuery->PostDNS = PostDNS;
+
+       InitC_ares_dns(IO);
 
-       IO->PostDNS = PostDNS;
        switch(Type) {
        case ns_t_a:
-               IO->DNS_CB = ParseAnswerA;
+               IO->DNSQuery->DNS_CB = ParseAnswerA;
                break;
 
        case ns_t_aaaa:
-               IO->DNS_CB = ParseAnswerAAAA;
+               IO->DNSQuery->DNS_CB = ParseAnswerAAAA;
                break;
 
        case ns_t_mx:
-               IO->DNS_CB = ParseAnswerMX;
+               IO->DNSQuery->DNS_CB = ParseAnswerMX;
                break;
 
        case ns_t_ns:
-               IO->DNS_CB = ParseAnswerNS;
+               IO->DNSQuery->DNS_CB = ParseAnswerNS;
                break;
 
        case ns_t_txt:
-               IO->DNS_CB = ParseAnswerTXT;
+               IO->DNSQuery->DNS_CB = ParseAnswerTXT;
                break;
 
        case ns_t_srv:
-               IO->DNS_CB = ParseAnswerSRV;
+               IO->DNSQuery->DNS_CB = ParseAnswerSRV;
                break;
 
        case ns_t_cname:
-               IO->DNS_CB = ParseAnswerCNAME;
+               IO->DNSQuery->DNS_CB = ParseAnswerCNAME;
                break;
 
        case ns_t_ptr:
@@ -292,28 +341,57 @@ int QueueQuery(ns_type Type, char *name, AsyncIO *IO, IO_CallBack PostDNS)
        return 1;
 }
 
-static void DNS_io_callback(struct ev_loop *loop, ev_io *watcher, int revents)
+
+
+
+
+/*****************************************************************************
+ *                   libevent / c-ares integration                           *
+ *****************************************************************************/
+static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
+{
+       AsyncIO *IO = watcher->data;
+       
+       ares_process_fd(IO->DNSChannel, ARES_SOCKET_BAD, IO->dns_send_event.fd);
+}
+static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
 {
        AsyncIO *IO = watcher->data;
        
-       ares_process_fd(IO->DNSChannel, IO->dns_io_event.fd, 0);
+       ares_process_fd(IO->DNSChannel, IO->dns_recv_event.fd, ARES_SOCKET_BAD);
 }
 
 void SockStateCb(void *data, int sock, int read, int write) 
 {
+/*
        struct timeval tvbuf, maxtv, *ret;
        
        int64_t time = 10;
+*/
        AsyncIO *IO = data;
 /* already inside of the event queue. */       
 
-       if (IO->dns_io_event.fd != sock) {
-               if (IO->dns_io_event.fd != 0) {
-                       ev_io_stop(event_base, &IO->dns_io_event);
+       if (read) {
+               if ((IO->dns_recv_event.fd != sock) &&
+                   (IO->dns_recv_event.fd != 0)) {
+                       ev_io_stop(event_base, &IO->dns_recv_event);
+               }
+               IO->dns_recv_event.fd = sock;
+               ev_io_init(&IO->dns_recv_event, DNS_recv_callback, IO->dns_recv_event.fd, EV_READ);
+               IO->dns_recv_event.data = IO;
+               ev_io_start(event_base, &IO->dns_recv_event);
+       } 
+       if (write) {
+               if ((IO->dns_send_event.fd != sock) &&
+                   (IO->dns_send_event.fd != 0)) {
+                       ev_io_stop(event_base, &IO->dns_send_event);
                }
-               IO->dns_io_event.fd = sock;
-               ev_io_init(&IO->dns_io_event, DNS_io_callback, IO->dns_io_event.fd, EV_READ|EV_WRITE);
-               IO->dns_io_event.data = IO;
+               IO->dns_send_event.fd = sock;
+               ev_io_init(&IO->dns_send_event, DNS_send_callback, IO->dns_send_event.fd, EV_WRITE);
+               IO->dns_send_event.data = IO;
+               ev_io_start(event_base, &IO->dns_send_event);
+       }
+/*
 
                ev_io_start(event_base, &IO->dns_io_event);
        
@@ -322,28 +400,23 @@ void SockStateCb(void *data, int sock, int read, int write)
                
                ret = ares_timeout(IO->DNSChannel, &maxtv, &tvbuf);
        }
+*/
+       if ((read == 0) && (write == 0)) {
+               ev_io_stop(event_base, &IO->dns_recv_event);
+               ev_io_stop(event_base, &IO->dns_send_event);
+       }
 }
 
 CTDL_MODULE_INIT(c_ares_client)
 {
        if (!threading)
        {
-               int optmask = 0;
-               
-
                int r = ares_library_init(ARES_LIB_INIT_ALL);
                if (0 != r) {
                        // TODO
                        // ThrowException(Exception::Error(String::New(ares_strerror(r))));
 ////                   assert(r == 0);
                }
-
-               optmask |= ARES_OPT_SOCK_STATE_CB;
-               memset(&options, 0, sizeof(struct ares_options));
-               options.sock_state_cb = SockStateCb;
-               
-               ares_init_options(&Channel, &options, optmask);
-
        }
        return "c-ares";
 }