Back to index

citadel  8.12
serv_c-ares-dns.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1998-2012 by the citadel.org team
00003  *
00004  *  This program is open source software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License version 3.
00006  *  
00007  *  
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  
00015  *  
00016  *  
00017  *
00018  *  Inspired by NodeJS.org; thanks for the MX-Parser ;-)
00019  */
00020 
00021 #include "sysdep.h"
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <stdio.h>
00025 #include <termios.h>
00026 #include <fcntl.h>
00027 #include <signal.h>
00028 #include <pwd.h>
00029 #include <errno.h>
00030 #include <sys/types.h>
00031 #include <syslog.h>
00032 
00033 #if TIME_WITH_SYS_TIME
00034 # include <sys/time.h>
00035 # include <time.h>
00036 #else
00037 # if HAVE_SYS_TIME_H
00038 #  include <sys/time.h>
00039 # else
00040 #  include <time.h>
00041 # endif
00042 #endif
00043 #include <sys/wait.h>
00044 #include <ctype.h>
00045 #include <string.h>
00046 #include <limits.h>
00047 #include <sys/socket.h>
00048 #include <netinet/in.h>
00049 #include <arpa/inet.h>
00050 
00051 #include <libcitadel.h>
00052 #include "citadel.h"
00053 #include "server.h"
00054 #include "citserver.h"
00055 #include "support.h"
00056 
00057 #include "ctdl_module.h"
00058 #include "event_client.h"
00059 
00060 int DebugCAres = 0;
00061 
00062 extern struct ev_loop *event_base;
00063 
00064 void SockStateCb(void *data, int sock, int read, int write);
00065 
00066 
00067 static void HostByAddrCb(void *data,
00068                       int status,
00069                       int timeouts,
00070                       struct hostent *hostent)
00071 {
00072        AsyncIO *IO = data;
00073 
00074        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00075 
00076        EV_DNS_LOGT_STOP(DNS.timeout);
00077        ev_timer_stop (event_base, &IO->DNS.timeout);
00078 
00079        IO->DNS.Query->DNSStatus = status;
00080        if  (status != ARES_SUCCESS) {
00081               StrBufPlain(IO->ErrMsg, ares_strerror(status), -1);
00082               return;
00083        }
00084        IO->DNS.Query->Data = hostent;
00085 }
00086 
00087 static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen)
00088 {
00089        struct hostent* host = NULL;
00090 
00091        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00092 
00093        if (IO->DNS.Query->VParsedDNSReply != NULL)
00094               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00095        IO->DNS.Query->VParsedDNSReply = NULL;
00096 
00097        IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
00098                                                 alen,
00099                                                 &host,
00100                                                 NULL,
00101                                                 NULL);
00102        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00103               if (host != NULL)
00104                      ares_free_hostent(host);
00105               StrBufPlain(IO->ErrMsg,
00106                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00107               return;
00108        }
00109        IO->DNS.Query->VParsedDNSReply = host;
00110        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
00111 }
00112 
00113 
00114 static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen)
00115 {
00116        struct hostent* host = NULL;
00117 
00118        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00119 
00120        if (IO->DNS.Query->VParsedDNSReply != NULL)
00121               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00122        IO->DNS.Query->VParsedDNSReply = NULL;
00123 
00124        IO->DNS.Query->DNSStatus = ares_parse_aaaa_reply(abuf,
00125                                                   alen,
00126                                                   &host,
00127                                                   NULL,
00128                                                   NULL);
00129        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00130               if (host != NULL)
00131                      ares_free_hostent(host);
00132               StrBufPlain(IO->ErrMsg,
00133                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00134               return;
00135        }
00136        IO->DNS.Query->VParsedDNSReply = host;
00137        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
00138 }
00139 
00140 
00141 static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen)
00142 {
00143        struct hostent* host = NULL;
00144 
00145        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00146 
00147        if (IO->DNS.Query->VParsedDNSReply != NULL)
00148               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00149        IO->DNS.Query->VParsedDNSReply = NULL;
00150 
00151        IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf,
00152                                                 alen,
00153                                                 &host,
00154                                                 NULL,
00155                                                 NULL);
00156        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00157               if (host != NULL)
00158                      ares_free_hostent(host);
00159               StrBufPlain(IO->ErrMsg,
00160                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00161               return;
00162        }
00163 
00164        // a CNAME lookup always returns a single record but
00165        IO->DNS.Query->VParsedDNSReply = host;
00166        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
00167 }
00168 
00169 
00170 static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen)
00171 {
00172        struct ares_mx_reply *mx_out = NULL;
00173 
00174        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00175 
00176        if (IO->DNS.Query->VParsedDNSReply != NULL)
00177               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00178        IO->DNS.Query->VParsedDNSReply = NULL;
00179 
00180        IO->DNS.Query->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out);
00181        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00182               if (mx_out != NULL)
00183                      ares_free_data(mx_out);
00184               StrBufPlain(IO->ErrMsg,
00185                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00186               return;
00187        }
00188 
00189        IO->DNS.Query->VParsedDNSReply = mx_out;
00190        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
00191 }
00192 
00193 
00194 static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen)
00195 {
00196        struct hostent* host = NULL;
00197 
00198        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00199 
00200        if (IO->DNS.Query->VParsedDNSReply != NULL)
00201               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00202        IO->DNS.Query->VParsedDNSReply = NULL;
00203 
00204        IO->DNS.Query->DNSStatus = ares_parse_ns_reply(abuf, alen, &host);
00205        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00206               if (host != NULL)
00207                      ares_free_hostent(host);
00208               StrBufPlain(IO->ErrMsg,
00209                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00210               return;
00211        }
00212        IO->DNS.Query->VParsedDNSReply = host;
00213        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
00214 }
00215 
00216 
00217 static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen)
00218 {
00219        struct ares_srv_reply *srv_out = NULL;
00220 
00221        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00222 
00223        if (IO->DNS.Query->VParsedDNSReply != NULL)
00224               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00225        IO->DNS.Query->VParsedDNSReply = NULL;
00226 
00227        IO->DNS.Query->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out);
00228        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00229               if (srv_out != NULL)
00230                      ares_free_data(srv_out);
00231               StrBufPlain(IO->ErrMsg,
00232                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00233               return;
00234        }
00235 
00236        IO->DNS.Query->VParsedDNSReply = srv_out;
00237        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
00238 }
00239 
00240 
00241 static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen)
00242 {
00243        struct ares_txt_reply *txt_out;
00244 
00245        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00246 
00247        if (IO->DNS.Query->VParsedDNSReply != NULL)
00248               IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply);
00249        IO->DNS.Query->VParsedDNSReply = NULL;
00250 
00251        IO->DNS.Query->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out);
00252        if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) {
00253               if (txt_out != NULL)
00254                      ares_free_data(txt_out);
00255               StrBufPlain(IO->ErrMsg,
00256                          ares_strerror(IO->DNS.Query->DNSStatus), -1);
00257               return;
00258        }
00259        IO->DNS.Query->VParsedDNSReply = txt_out;
00260        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data;
00261 }
00262 
00263 void QueryCb(void *arg,
00264             int status,
00265             int timeouts,
00266             unsigned char* abuf,
00267             int alen)
00268 {
00269        AsyncIO *IO = arg;
00270 
00271        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00272 
00273        EV_DNS_LOGT_STOP(DNS.timeout);
00274        ev_timer_stop (event_base, &IO->DNS.timeout);
00275 
00276        IO->DNS.Query->DNSStatus = status;
00277        if (status == ARES_SUCCESS)
00278               IO->DNS.Query->DNS_CB(arg, abuf, alen);
00279        else {
00280               EV_DNS_syslog(LOG_DEBUG, "C-ARES: Failed by: %s error %s\n",
00281                            __FUNCTION__,
00282                            ares_strerror(status));
00283               StrBufPlain(IO->ErrMsg, ares_strerror(status), -1);
00284               IO->DNS.Query->DNSStatus = status;
00285        }
00286 
00287        ev_idle_init(&IO->unwind_stack,
00288                    IO_postdns_callback);
00289        IO->unwind_stack.data = IO;
00290        EV_DNS_LOGT_INIT(unwind_stack);
00291        EV_DNS_LOGT_START(unwind_stack);
00292        ev_idle_start(event_base, &IO->unwind_stack);
00293 }
00294 
00295 void QueryCbDone(AsyncIO *IO)
00296 {
00297        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00298 
00299        EV_DNS_LOGT_STOP(DNS.timeout);
00300        ev_timer_stop (event_base, &IO->DNS.timeout);
00301 
00302        EV_DNS_LOGT_STOP(unwind_stack);
00303        ev_idle_stop(event_base, &IO->unwind_stack);
00304 }
00305 
00306 void DestructCAres(AsyncIO *IO)
00307 {
00308        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00309 
00310        EV_DNS_LOG_STOP(DNS.recv_event);
00311        ev_io_stop(event_base, &IO->DNS.recv_event);
00312 
00313        EV_DNS_LOG_STOP(DNS.send_event);
00314        ev_io_stop(event_base, &IO->DNS.send_event);
00315 
00316        EV_DNS_LOGT_STOP(DNS.timeout);
00317        ev_timer_stop (event_base, &IO->DNS.timeout);
00318 
00319        EV_DNS_LOGT_STOP(unwind_stack);
00320        ev_idle_stop(event_base, &IO->unwind_stack);
00321        ares_destroy_options(&IO->DNS.Options);
00322 }
00323 
00324 
00325 void InitC_ares_dns(AsyncIO *IO)
00326 {
00327        int optmask = 0;
00328 
00329        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s %p\n", __FUNCTION__, IO->DNS.Channel);
00330 
00331        if (IO->DNS.Channel == NULL) {
00332               optmask |= ARES_OPT_SOCK_STATE_CB;
00333               IO->DNS.Options.sock_state_cb = SockStateCb;
00334               IO->DNS.Options.sock_state_cb_data = IO;
00335               ares_init_options(&IO->DNS.Channel, &IO->DNS.Options, optmask);
00336        }
00337        IO->DNS.Query->DNSStatus = 0;
00338 }
00339 
00340 static void
00341 DNStimeouttrigger_callback(struct ev_loop *loop, ev_timer *watcher, int revents)
00342 {
00343        AsyncIO *IO = watcher->data;
00344        struct timeval tv, MaxTV;
00345        struct timeval *NextTV;
00346 
00347        memset(&MaxTV, 0, sizeof(MaxTV));
00348        memset(&tv, 0, sizeof(tv));
00349        MaxTV.tv_sec = 30;
00350        NextTV = ares_timeout(IO->DNS.Channel, &MaxTV, &tv);
00351 
00352        if ((NextTV->tv_sec != MaxTV.tv_sec) ||
00353            (NextTV->tv_usec != MaxTV.tv_usec))
00354        {
00355               fd_set readers, writers;
00356               EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s Timeout!\n", __FUNCTION__);
00357 
00358               FD_ZERO(&readers);
00359               FD_ZERO(&writers);
00360               ares_fds(IO->DNS.Channel, &readers, &writers);
00361               ares_process(IO->DNS.Channel, &readers, &writers);
00362        }
00363 }
00364 
00365 void QueueGetHostByNameDone(void *Ctx,
00366                          int status,
00367                          int timeouts,
00368                          struct hostent *hostent)
00369 {
00370        AsyncIO *IO = (AsyncIO *) Ctx;
00371 
00372        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00373 
00374 
00375        IO->DNS.Query->DNSStatus = status;
00376        IO->DNS.Query->VParsedDNSReply = hostent;
00377        IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent;
00378 
00379        EV_DNS_LOGT_STOP(DNS.timeout);
00380        ev_timer_stop (event_base, &IO->DNS.timeout);
00381 
00382        ev_idle_init(&IO->unwind_stack,
00383                    IO_postdns_callback);
00384        IO->unwind_stack.data = IO;
00385        EV_DNS_LOGT_INIT(unwind_stack);
00386        EV_DNS_LOGT_START(unwind_stack);
00387        ev_idle_start(event_base, &IO->unwind_stack);
00388 
00389 }
00390 
00391 void QueueGetHostByName(AsyncIO *IO,
00392                      const char *Hostname,
00393                      DNSQueryParts *QueryParts,
00394                      IO_CallBack PostDNS)
00395 {
00396 
00397        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00398        IO->DNS.SourcePort = 0;
00399 
00400        IO->DNS.Query = QueryParts;
00401        IO->DNS.Query->PostDNS = PostDNS;
00402 
00403        InitC_ares_dns(IO);
00404 
00405        ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
00406        EV_DNS_LOGT_INIT(DNS.timeout);
00407        IO->DNS.timeout.data = IO;
00408        ares_gethostbyname(IO->DNS.Channel,
00409                         Hostname,
00410                         AF_INET6, /* it falls back to ipv4 in doubt... */
00411                         QueueGetHostByNameDone,
00412                         IO);
00413        EV_DNS_LOGT_START(DNS.timeout);
00414        ev_timer_start(event_base, &IO->DNS.timeout);
00415 
00416 }
00417 
00418 int QueueQuery(ns_type Type,
00419               const char *name,
00420               AsyncIO *IO,
00421               DNSQueryParts *QueryParts,
00422               IO_CallBack PostDNS)
00423 {
00424        int length, family;
00425        char address_b[sizeof(struct in6_addr)];
00426 
00427        IO->DNS.SourcePort = 0;
00428 
00429        IO->DNS.Query = QueryParts;
00430        IO->DNS.Query->PostDNS = PostDNS;
00431        IO->DNS.Start = IO->Now;
00432 
00433        InitC_ares_dns(IO);
00434 
00435        ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1);
00436        IO->DNS.timeout.data = IO;
00437        EV_DNS_LOGT_INIT(DNS.timeout);
00438 
00439        switch(Type) {
00440        case ns_t_a:
00441               IO->DNS.Query->DNS_CB = ParseAnswerA;
00442               break;
00443 
00444        case ns_t_aaaa:
00445               IO->DNS.Query->DNS_CB = ParseAnswerAAAA;
00446               break;
00447 
00448        case ns_t_mx:
00449               IO->DNS.Query->DNS_CB = ParseAnswerMX;
00450               break;
00451 
00452        case ns_t_ns:
00453               IO->DNS.Query->DNS_CB = ParseAnswerNS;
00454               break;
00455 
00456        case ns_t_txt:
00457               IO->DNS.Query->DNS_CB = ParseAnswerTXT;
00458               break;
00459 
00460        case ns_t_srv:
00461               IO->DNS.Query->DNS_CB = ParseAnswerSRV;
00462               break;
00463 
00464        case ns_t_cname:
00465               IO->DNS.Query->DNS_CB = ParseAnswerCNAME;
00466               break;
00467 
00468        case ns_t_ptr:
00469 
00470 
00471               if (inet_pton(AF_INET, name, &address_b) == 1) {
00472                      length = sizeof(struct in_addr);
00473                      family = AF_INET;
00474               } else if (inet_pton(AF_INET6, name, &address_b) == 1) {
00475                      length = sizeof(struct in6_addr);
00476                      family = AF_INET6;
00477               } else {
00478                      return -1;
00479               }
00480 
00481               ares_gethostbyaddr(IO->DNS.Channel,
00482                                address_b,
00483                                length,
00484                                family,
00485                                HostByAddrCb,
00486                                IO);
00487               EV_DNS_LOGT_START(DNS.timeout);
00488               ev_timer_start(event_base, &IO->DNS.timeout);
00489 
00490               EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s X1\n", __FUNCTION__);
00491 
00492               return 1;
00493 
00494        default:
00495 
00496               EV_DNS_syslog(LOG_DEBUG, "C-ARES: %sX2\n", __FUNCTION__);
00497               return 0;
00498        }
00499        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00500 
00501        ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO);
00502        EV_DNS_LOGT_START(DNS.timeout);
00503        ev_timer_start(event_base, &IO->DNS.timeout);
00504        return 1;
00505 }
00506 
00507 
00508 
00509 
00510 
00511 /*****************************************************************************
00512  *                      libev / c-ares integration                           *
00513  *****************************************************************************/
00514 static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents)
00515 {
00516        AsyncIO *IO = watcher->data;
00517 
00518        IO->Now = ev_now(event_base);
00519 
00520        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00521 
00522        ares_process_fd(IO->DNS.Channel,
00523                      ARES_SOCKET_BAD,
00524                      IO->DNS.send_event.fd);
00525 }
00526 static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents)
00527 {
00528        AsyncIO *IO = watcher->data;
00529 
00530        IO->Now = ev_now(event_base);
00531 
00532        EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__);
00533 
00534        ares_process_fd(IO->DNS.Channel,
00535                      IO->DNS.recv_event.fd,
00536                      ARES_SOCKET_BAD);
00537 }
00538 
00539 void SockStateCb(void *data, int sock, int read, int write)
00540 {
00541        AsyncIO *IO = data;
00542 /* already inside of the event queue. */
00543        if (DebugCAres)
00544        {
00545               struct sockaddr_in sin = {};
00546               socklen_t slen;
00547               slen = sizeof(sin);
00548               if ((IO->DNS.SourcePort == 0) &&
00549                   (getsockname(sock, &sin, &slen) == 0))
00550               {
00551                      IO->DNS.SourcePort = ntohs(sin.sin_port);
00552               }
00553               EV_DNS_syslog(LOG_DEBUG, "C-ARES: %s %d|%d Sock %d port %hu\n",
00554                            __FUNCTION__,
00555                            read,
00556                            write,
00557                            sock,
00558                            IO->DNS.SourcePort);
00559        }
00560 
00561        IO->Now = ev_now(event_base);
00562 
00563        if (read) {
00564               if ((IO->DNS.recv_event.fd != sock) &&
00565                   (IO->DNS.recv_event.fd != 0)) {
00566                      EV_DNS_LOG_STOP(DNS.recv_event);
00567                      ev_io_stop(event_base, &IO->DNS.recv_event);
00568               }
00569               IO->DNS.recv_event.fd = sock;
00570               ev_io_init(&IO->DNS.recv_event,
00571                         DNS_recv_callback,
00572                         IO->DNS.recv_event.fd,
00573                         EV_READ);
00574               EV_DNS_LOG_INIT(DNS.recv_event);
00575               IO->DNS.recv_event.data = IO;
00576               EV_DNS_LOG_START(DNS.recv_event);
00577               ev_io_start(event_base, &IO->DNS.recv_event);
00578        }
00579        if (write) {
00580               if ((IO->DNS.send_event.fd != sock) &&
00581                   (IO->DNS.send_event.fd != 0)) {
00582                      EV_DNS_LOG_STOP(DNS.send_event);
00583                      ev_io_stop(event_base, &IO->DNS.send_event);
00584               }
00585               IO->DNS.send_event.fd = sock;
00586               ev_io_init(&IO->DNS.send_event,
00587                         DNS_send_callback,
00588                         IO->DNS.send_event.fd,
00589                         EV_WRITE);
00590               IO->DNS.send_event.data = IO;
00591               EV_DNS_LOG_INIT(DNS.send_event);
00592               EV_DNS_LOG_START(DNS.send_event);
00593               ev_io_start(event_base, &IO->DNS.send_event);
00594        }
00595        if ((read == 0) && (write == 0)) {
00596               EV_DNS_LOG_STOP(DNS.recv_event);
00597               EV_DNS_LOG_STOP(DNS.send_event);
00598               ev_io_stop(event_base, &IO->DNS.recv_event);
00599               ev_io_stop(event_base, &IO->DNS.send_event);
00600        }
00601 }
00602 void EnableDebugCAres(const int n)
00603 {
00604        DebugCAres = n;
00605 }
00606 
00607 CTDL_MODULE_INIT(c_ares_client)
00608 {
00609        if (!threading)
00610        {
00611               CtdlRegisterDebugFlagHook(HKEY("cares"), EnableDebugCAres, &DebugCAres);
00612               int r = ares_library_init(ARES_LIB_INIT_ALL);
00613               if (0 != r) {
00614                      
00615               }
00616        }
00617        return "c-ares";
00618 }