X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fc-ares-dns%2Fserv_c-ares-dns.c;h=13e156a80879a3ecb17ceb7e8e318d839a59cea9;hb=72a4e9f304cff9f487b334f0d70f09142fee4183;hp=07e44a11351a4e789a5bf16fe33261d41b45a44e;hpb=ed1626a8680415154da2f2f81d943e7bbbadc717;p=citadel.git diff --git a/citadel/modules/c-ares-dns/serv_c-ares-dns.c b/citadel/modules/c-ares-dns/serv_c-ares-dns.c index 07e44a113..13e156a80 100644 --- a/citadel/modules/c-ares-dns/serv_c-ares-dns.c +++ b/citadel/modules/c-ares-dns/serv_c-ares-dns.c @@ -1,19 +1,19 @@ /* - * Copyright (c) 1998-2009 by the citadel.org team + * Copyright (c) 1998-2012 by the citadel.org team * - * 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 open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * + * * * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * * * Inspired by NodeJS.org; thanks for the MX-Parser ;-) */ @@ -57,449 +57,418 @@ #include "ctdl_module.h" #include "event_client.h" +int DebugCAres = 0; extern struct ev_loop *event_base; -struct ares_options options; -ares_channel Channel; void SockStateCb(void *data, int sock, int read, int write); -/* - c-ares beim connect zum nameserver: if (channel->sock_create_cb) - - SOCK_STATE_CALLBACK(channel, s, 1, 0); -> void Channel::SockStateCb(void *data, int sock, int read, int write) { - - - -lesen der antwort: -#0 node::Channel::QueryCb (arg=0x8579268, status=0x0, timeouts=0x0, abuf=0xbffff0ef "\356|\201\200", alen=0x48) at ../src/node_cares.cc:453 -#1 0x08181884 in qcallback (arg=0x8579278, status=0x857b5a0, timeouts=0x0, abuf=0xbffff0ef "\356|\201\200", alen=0x48) at ../deps/c-ares/ares_query.c:180 -#2 0x0817fbf5 in end_query (channel=, query=0x85790b0, status=0x1, abuf=0xbffff0ef "\356|\201\200", alen=0x48) at ../deps/c-ares/ares_process.c:1233 -#3 0x08180898 in process_answer (channel=, abuf=, alen=, whichserver=0x0, tcp=0x0, now=0xbffff388) at ../deps/c-ares/ares_process.c:612 -#4 0x08180cf8 in read_udp_packets (channel=, read_fds=, read_fd=, now=0xbffff388) at ../deps/c-ares/ares_process.c:498 -#5 0x08181021 in processfds (channel=0x85a9888, read_fds=, read_fd=, write_fds=0x0, write_fd=0xffffffff) at ../deps/c-ares/ares_process.c:153 - --> -static void ParseAnswerMX(QueryArg *arg, unsigned char* abuf, int alen) { - HandleScope scope; - - - - */ - -/* - -static Local HostEntToAddresses(struct hostent* hostent) { - Local addresses = Array::New(); - - - char ip[INET6_ADDRSTRLEN]; - for (int i = 0; hostent->h_addr_list[i]; ++i) { - inet_ntop(hostent->h_addrtype, hostent->h_addr_list[i], ip, sizeof(ip)); - - Local address = String::New(ip); - addresses->Set(Integer::New(i), address); - } - - return addresses; -} - - -static Local HostEntToNames(struct hostent* hostent) { - Local names = Array::New(); - - for (int i = 0; hostent->h_aliases[i]; ++i) { - Local address = String::New(hostent->h_aliases[i]); - names->Set(Integer::New(i), address); - } - - return names; -} - -static inline const char *ares_errno_string(int errorno) { -#define ERRNO_CASE(e) case ARES_##e: return #e; - switch (errorno) { - ERRNO_CASE(SUCCESS) - ERRNO_CASE(ENODATA) - ERRNO_CASE(EFORMERR) - ERRNO_CASE(ESERVFAIL) - ERRNO_CASE(ENOTFOUND) - ERRNO_CASE(ENOTIMP) - ERRNO_CASE(EREFUSED) - ERRNO_CASE(EBADQUERY) - ERRNO_CASE(EBADNAME) - ERRNO_CASE(EBADFAMILY) - ERRNO_CASE(EBADRESP) - ERRNO_CASE(ECONNREFUSED) - ERRNO_CASE(ETIMEOUT) - ERRNO_CASE(EOF) - ERRNO_CASE(EFILE) - ERRNO_CASE(ENOMEM) - ERRNO_CASE(EDESTRUCTION) - ERRNO_CASE(EBADSTR) - ERRNO_CASE(EBADFLAGS) - ERRNO_CASE(ENONAME) - ERRNO_CASE(EBADHINTS) - ERRNO_CASE(ENOTINITIALIZED) - ERRNO_CASE(ELOADIPHLPAPI) - ERRNO_CASE(EADDRGETNETWORKPARAMS) - ERRNO_CASE(ECANCELLED) - default: - assert(0 && "Unhandled c-ares errno"); - return "(UNKNOWN)"; - } -} - - -static void ResolveError(Persistent &cb, int status) { - HandleScope scope; - - Local code = String::NewSymbol(ares_errno_string(status)); - Local message = String::NewSymbol(ares_strerror(status)); - - Local cons1 = String::Concat(code, String::NewSymbol(", ")); - Local cons2 = String::Concat(cons1, message); - - Local e = Exception::Error(cons2); - - Local obj = e->ToObject(); - obj->Set(String::NewSymbol("errno"), Integer::New(status)); - - TryCatch try_catch; - - cb->Call(v8::Context::GetCurrent()->Global(), 1, &e); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } -} - -static void HostByNameCb(void *data, - int status, - int timeouts, - struct hostent *hostent) { - HandleScope scope; - - Persistent *cb = cb_unwrap(data); - - if (status != ARES_SUCCESS) { - ResolveError(*cb, status); - cb_destroy(cb); - return; - } - - TryCatch try_catch; - - Local addresses = HostEntToAddresses(hostent); - - Local argv[2] = { Local::New(Null()), addresses}; - - (*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } - - cb_destroy(cb); -} - - - - -static void cb_call(Persistent &cb, int argc, Local *argv) { - TryCatch try_catch; - - cb->Call(v8::Context::GetCurrent()->Global(), argc, argv); - - if (try_catch.HasCaught()) { - FatalException(try_catch); - } -} - -Handle Channel::GetHostByAddr(const Arguments& args) { - HandleScope scope; - Channel *c = ObjectWrap::Unwrap(args.Holder()); - assert(c); - - if (!args[0]->IsString()) { - return ThrowException(Exception::Error( - String::New("First argument must be a address"))); - } - - if (!args[1]->IsInt32()) { - return ThrowException(Exception::Error( - String::New("Second argument must be an address family"))); - } - - if (!args[2]->IsFunction()) { - return ThrowException(Exception::Error( - String::New("Third argument must be a callback"))); - } - - int family = args[1]->Int32Value(); - if (family != AF_INET6 && family != AF_INET) { - return ThrowException(Exception::Error( - String::New("Unsupported address family"))); - } - - String::Utf8Value address_s(args[0]->ToString()); - - char address_b[sizeof(struct in6_addr)]; - int r = inet_pton(family, *address_s, address_b); - if (r != 1) { - return ThrowException(Exception::Error( - String::New("Invalid network address"))); - } - - int length; - if (family == AF_INET6) - length = sizeof(struct in6_addr); - else - length = sizeof(struct in_addr); - - ares_gethostbyaddr(c->channel, address_b, length, family, HostByAddrCb, cb_persist(args[2])); - - return Undefined(); -} - - - -Handle Channel::GetHostByName(const Arguments& args) { - HandleScope scope; - Channel *c = ObjectWrap::Unwrap(args.Holder()); - assert(c); - - if (!args[0]->IsString()) { - return ThrowException(Exception::Error( - String::New("First argument must be a name"))); - } - - if (!args[1]->IsInt32()) { - return ThrowException(Exception::Error( - String::New("Second argument must be a family"))); - } - - if (!args[2]->IsFunction()) { - return ThrowException(Exception::Error( - String::New("Third argument must be a callback"))); - } - - int family = args[1]->Int32Value(); - if (family != AF_INET6 && family != AF_INET) { - return ThrowException(Exception::Error( - String::New("Unsupported address family"))); - } - - String::Utf8Value name(args[0]->ToString()); - - ares_gethostbyname(c->channel, *name, family, HostByNameCb, cb_persist(args[2])); - - return Undefined(); -} - -*/ - - static void HostByAddrCb(void *data, - int status, - int timeouts, - struct hostent *hostent) + int status, + int timeouts, + struct hostent *hostent) { AsyncIO *IO = data; - IO->DNSStatus = status; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); + EV_DNS_LOGT_STOP(DNS.timeout); +#endif + ev_timer_stop (event_base, &IO->DNS.timeout); + + IO->DNS.Query->DNSStatus = status; if (status != ARES_SUCCESS) { -// ResolveError(*cb, status); + StrBufPlain(IO->ErrMsg, ares_strerror(status), -1); return; } - IO->Data = hostent; -/// TODO: howto free this?? + IO->DNS.Query->Data = hostent; } -static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen) { - struct hostent* host; - - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + struct hostent* host = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - IO->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; + + IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf, + alen, + &host, + NULL, + NULL); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (host != NULL) + ares_free_hostent(host); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = host; - IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent; + IO->DNS.Query->VParsedDNSReply = host; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; } -static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen) { - struct hostent* host; - - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + struct hostent* host = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - IO->DNSStatus = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; + + IO->DNS.Query->DNSStatus = ares_parse_aaaa_reply(abuf, + alen, + &host, + NULL, + NULL); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (host != NULL) + ares_free_hostent(host); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = host; - IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent; + IO->DNS.Query->VParsedDNSReply = host; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; } -static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen) { - struct hostent* host; + struct hostent* host = NULL; - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - IO->DNSStatus = ares_parse_a_reply(abuf, alen, &host, NULL, NULL); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; + + IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf, + alen, + &host, + NULL, + NULL); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (host != NULL) + ares_free_hostent(host); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } // a CNAME lookup always returns a single record but - IO->VParsedDNSReply = host; - IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent; + IO->DNS.Query->VParsedDNSReply = host; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; } -static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen) { - struct ares_mx_reply *mx_out; + struct ares_mx_reply *mx_out = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; - IO->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + IO->DNS.Query->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (mx_out != NULL) + ares_free_data(mx_out); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = mx_out; - IO->DNSReplyFree = (FreeDNSReply) ares_free_data; + IO->DNS.Query->VParsedDNSReply = mx_out; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; } -static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen) { - struct hostent* host; + struct hostent* host = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; - IO->DNSStatus = ares_parse_ns_reply(abuf, alen, &host); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + IO->DNS.Query->DNSStatus = ares_parse_ns_reply(abuf, alen, &host); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (host != NULL) + ares_free_hostent(host); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = host; - IO->DNSReplyFree = (FreeDNSReply) ares_free_hostent; + IO->DNS.Query->VParsedDNSReply = host; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; } -static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen) { - struct ares_srv_reply *srv_out; + struct ares_srv_reply *srv_out = NULL; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; - IO->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + IO->DNS.Query->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (srv_out != NULL) + ares_free_data(srv_out); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = srv_out; - IO->DNSReplyFree = (FreeDNSReply) ares_free_data; + IO->DNS.Query->VParsedDNSReply = srv_out; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; } -static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen) +static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen) { struct ares_txt_reply *txt_out; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif - if (IO->VParsedDNSReply != NULL) - IO->DNSReplyFree(IO->VParsedDNSReply); - IO->VParsedDNSReply = NULL; + if (IO->DNS.Query->VParsedDNSReply != NULL) + IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); + IO->DNS.Query->VParsedDNSReply = NULL; - IO->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out); - if (IO->DNSStatus != ARES_SUCCESS) { -// ResolveError(arg->js_cb, status); + IO->DNS.Query->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out); + if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { + if (txt_out != NULL) + ares_free_data(txt_out); + StrBufPlain(IO->ErrMsg, + ares_strerror(IO->DNS.Query->DNSStatus), -1); return; } - IO->VParsedDNSReply = txt_out; - IO->DNSReplyFree = (FreeDNSReply) ares_free_data; + IO->DNS.Query->VParsedDNSReply = txt_out; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; } - void QueryCb(void *arg, int status, int timeouts, unsigned char* abuf, - int alen) + int alen) { AsyncIO *IO = arg; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); + EV_DNS_LOGT_STOP(DNS.timeout); +#endif + ev_timer_stop (event_base, &IO->DNS.timeout); - IO->DNSStatus = status; + IO->DNS.Query->DNSStatus = status; if (status == ARES_SUCCESS) - IO->DNS_CB(arg, abuf, alen); - IO->PostDNS(IO); + IO->DNS.Query->DNS_CB(arg, abuf, alen); + else { + EV_syslog(LOG_DEBUG, "C-ARES: Failed by: %s error %s\n", + __FUNCTION__, + ares_strerror(status)); + StrBufPlain(IO->ErrMsg, ares_strerror(status), -1); + IO->DNS.Query->DNSStatus = status; + } + + ev_idle_init(&IO->unwind_stack, + IO_postdns_callback); + IO->unwind_stack.data = IO; + EV_DNS_LOGT_INIT(unwind_stack); + EV_DNS_LOGT_START(unwind_stack); + ev_idle_start(event_base, &IO->unwind_stack); } -int QueueQuery(ns_type Type, char *name, AsyncIO *IO, IO_CallBack PostDNS) +void QueryCbDone(AsyncIO *IO) +{ +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); + EV_DNS_LOGT_STOP(DNS.timeout); +#endif + + ev_idle_stop(event_base, &IO->unwind_stack); +} + +void DestructCAres(AsyncIO *IO) +{ +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); + EV_DNS_LOGT_STOP(DNS.timeout); +#endif + EV_DNS_LOG_STOP(DNS.recv_event); + ev_io_stop(event_base, &IO->DNS.recv_event); + EV_DNS_LOG_STOP(DNS.send_event); + ev_io_stop(event_base, &IO->DNS.send_event); + ev_timer_stop (event_base, &IO->DNS.timeout); + ev_idle_stop(event_base, &IO->unwind_stack); + ares_destroy_options(&IO->DNS.Options); +} + + +void InitC_ares_dns(AsyncIO *IO) +{ + int optmask = 0; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s %p\n", __FUNCTION__, IO->DNS.Channel); +#endif + + if (IO->DNS.Channel == NULL) { + optmask |= ARES_OPT_SOCK_STATE_CB; + IO->DNS.Options.sock_state_cb = SockStateCb; + IO->DNS.Options.sock_state_cb_data = IO; + ares_init_options(&IO->DNS.Channel, &IO->DNS.Options, optmask); + } + IO->DNS.Query->DNSStatus = 0; +} + +static void +DNStimeouttrigger_callback(struct ev_loop *loop, ev_timer *watcher, int revents) +{ + AsyncIO *IO = watcher->data; + struct timeval tv, MaxTV; + struct timeval *NextTV; + + memset(&MaxTV, 0, sizeof(MaxTV)); + memset(&tv, 0, sizeof(tv)); + MaxTV.tv_sec = 30; + NextTV = ares_timeout(IO->DNS.Channel, &MaxTV, &tv); + + if ((NextTV->tv_sec != MaxTV.tv_sec) || + (NextTV->tv_usec != MaxTV.tv_usec)) + { + fd_set readers, writers; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s Timeout!\n", __FUNCTION__); +#endif + FD_ZERO(&readers); + FD_ZERO(&writers); + ares_fds(IO->DNS.Channel, &readers, &writers); + ares_process(IO->DNS.Channel, &readers, &writers); + } +} + +void QueueGetHostByNameDone(void *Ctx, + int status, + int timeouts, + struct hostent *hostent) +{ + AsyncIO *IO = (AsyncIO *) Ctx; +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif + + IO->DNS.Query->DNSStatus = status; + IO->DNS.Query->VParsedDNSReply = hostent; + IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; + + ev_idle_init(&IO->unwind_stack, + IO_postdns_callback); + IO->unwind_stack.data = IO; + EV_DNS_LOGT_INIT(unwind_stack); + EV_DNS_LOGT_START(unwind_stack); + ev_idle_start(event_base, &IO->unwind_stack); + ev_timer_stop (event_base, &IO->DNS.timeout); +} + +void QueueGetHostByName(AsyncIO *IO, + const char *Hostname, + DNSQueryParts *QueryParts, + IO_CallBack PostDNS) +{ +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); + IO->DNS.SourcePort = 0; +#endif + + IO->DNS.Query = QueryParts; + IO->DNS.Query->PostDNS = PostDNS; + + InitC_ares_dns(IO); + + ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1); + EV_DNS_LOGT_INIT(DNS.timeout); + IO->DNS.timeout.data = IO; + ares_gethostbyname(IO->DNS.Channel, + Hostname, + AF_INET6, /* it falls back to ipv4 in doubt... */ + QueueGetHostByNameDone, + IO); + EV_DNS_LOGT_START(DNS.timeout); + ev_timer_start(event_base, &IO->DNS.timeout); + +} + +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)]; - int optmask = 0; - int rfd, wfd; - 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); +#ifdef DEBUG_CARES + IO->DNS.SourcePort = 0; +#endif + + IO->DNS.Query = QueryParts; + IO->DNS.Query->PostDNS = PostDNS; + IO->DNS.Start = IO->Now; + + InitC_ares_dns(IO); + + ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1); + IO->DNS.timeout.data = IO; + EV_DNS_LOGT_INIT(DNS.timeout); - IO->PostDNS = PostDNS; switch(Type) { case ns_t_a: - IO->DNS_CB = ParseAnswerA; + IO->DNS.Query->DNS_CB = ParseAnswerA; break; case ns_t_aaaa: - IO->DNS_CB = ParseAnswerAAAA; + IO->DNS.Query->DNS_CB = ParseAnswerAAAA; break; case ns_t_mx: - IO->DNS_CB = ParseAnswerMX; + IO->DNS.Query->DNS_CB = ParseAnswerMX; break; case ns_t_ns: - IO->DNS_CB = ParseAnswerNS; + IO->DNS.Query->DNS_CB = ParseAnswerNS; break; case ns_t_txt: - IO->DNS_CB = ParseAnswerTXT; + IO->DNS.Query->DNS_CB = ParseAnswerTXT; break; case ns_t_srv: - IO->DNS_CB = ParseAnswerSRV; + IO->DNS.Query->DNS_CB = ParseAnswerSRV; break; case ns_t_cname: - IO->DNS_CB = ParseAnswerCNAME; + IO->DNS.Query->DNS_CB = ParseAnswerCNAME; break; case ns_t_ptr: @@ -515,78 +484,146 @@ int QueueQuery(ns_type Type, char *name, AsyncIO *IO, IO_CallBack PostDNS) return -1; } - ares_gethostbyaddr(IO->DNSChannel, address_b, length, family, HostByAddrCb, IO); - + ares_gethostbyaddr(IO->DNS.Channel, + address_b, + length, + family, + HostByAddrCb, + IO); + EV_DNS_LOGT_START(DNS.timeout); + ev_timer_start(event_base, &IO->DNS.timeout); +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s X1\n", __FUNCTION__); +#endif return 1; default: +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %sX2\n", __FUNCTION__); +#endif return 0; } - ares_query(IO->DNSChannel, name, ns_c_in, Type, QueryCb, IO); - ares_fds(IO->DNSChannel, &rfd, &wfd); +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif + ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO); + EV_DNS_LOGT_START(DNS.timeout); + ev_timer_start(event_base, &IO->DNS.timeout); return 1; } -static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents) + + + + +/***************************************************************************** + * libev / 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, IO->sock, 0); -} -static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents) + IO->Now = ev_now(event_base); +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif + + ares_process_fd(IO->DNS.Channel, + 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, 0, IO->sock); + + IO->Now = ev_now(event_base); + +#ifdef DEBUG_CARES + EV_syslog(LOG_DEBUG, "C-ARES: %s\n", __FUNCTION__); +#endif + + ares_process_fd(IO->DNS.Channel, + IO->DNS.recv_event.fd, + ARES_SOCKET_BAD); } -void SockStateCb(void *data, int sock, int read, int write) +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. */ - IO->sock = sock; - ev_io_init(&IO->recv_event, DNS_recv_callback, IO->sock, EV_READ); - IO->recv_event.data = IO; - ev_io_init(&IO->send_event, DNS_send_callback, IO->sock, EV_WRITE); - IO->send_event.data = IO; - if (write) - ev_io_start(event_base, &IO->send_event); - else - ev_io_start(event_base, &IO->recv_event); - - - maxtv.tv_sec = time/1000; - maxtv.tv_usec = (time % 1000) * 1000; - - ret = ares_timeout(IO->DNSChannel, &maxtv, &tvbuf); - - +/* already inside of the event queue. */ +#ifdef DEBUG_CARES +{ + struct sockaddr_in sin = {}; + socklen_t slen; + slen = sizeof(sin); + if ((IO->DNS.SourcePort == 0) && + (getsockname(sock, &sin, &slen) == 0)) + { + IO->DNS.SourcePort = ntohs(sin.sin_port); + } + EV_syslog(LOG_DEBUG, "C-ARES: %s %d|%d Sock %d port %hu\n", + __FUNCTION__, + read, + write, + sock, + IO->DNS.SourcePort); +} +#endif + IO->Now = ev_now(event_base); + + if (read) { + if ((IO->DNS.recv_event.fd != sock) && + (IO->DNS.recv_event.fd != 0)) { + EV_DNS_LOG_STOP(DNS.recv_event); + 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); + EV_DNS_LOG_INIT(DNS.recv_event); + IO->DNS.recv_event.data = IO; + EV_DNS_LOG_START(DNS.recv_event); + 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_DNS_LOG_STOP(DNS.send_event); + ev_io_stop(event_base, &IO->DNS.send_event); + } + 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_DNS_LOG_INIT(DNS.send_event); + EV_DNS_LOG_START(DNS.send_event); + ev_io_start(event_base, &IO->DNS.send_event); + } + if ((read == 0) && (write == 0)) { + EV_DNS_LOG_STOP(DNS.recv_event); + EV_DNS_LOG_STOP(DNS.send_event); + ev_io_stop(event_base, &IO->DNS.recv_event); + ev_io_stop(event_base, &IO->DNS.send_event); + } +} +void EnableDebugCAres(void) +{ + DebugCAres = 1; } CTDL_MODULE_INIT(c_ares_client) { if (!threading) { - int optmask = 0; - - + CtdlRegisterDebugFlagHook(HKEY("cares"), EnableDebugCAres); 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"; }