+static void dnsengine_cares_callback(void *arg, int status, int timeouts, struct hostent *host) {
+ struct dnsengine_cares_query *query = arg;
+ struct _IODNSQuery *iodns = query->iodns;
+ query->query_count--;
+ if(iodns) {
+ if(!(iodns->flags & IODNSFLAG_RUNNING)) {
+ // query stopped
+ query->iodns = NULL;
+ iodns = NULL;
+ iodns_free_result(iodns->result);
+ _free_dnsquery(iodns);
+ }
+ if(iodns && status == ARES_SUCCESS) {
+ if((iodns->type & IODNS_FORWARD)) {
+ char **h_addr;
+ for(h_addr = host->h_addr_list; *h_addr; h_addr++) {
+ struct IODNSResult *dnsresult = malloc(sizeof(*dnsresult));
+ if(!dnsresult) {
+ iolog_trigger(IOLOG_ERROR, "Failed to allocate memory for IODNSResult in %s:%d", __FILE__, __LINE__);
+ goto dnsengine_cares_callback_finally;
+ }
+
+ int sockaddrlen;
+ if(host->h_addrtype == AF_INET) {
+ dnsresult->type = IODNS_RECORD_A;
+ sockaddrlen = sizeof(struct sockaddr_in);
+ } else {
+ dnsresult->type = IODNS_RECORD_AAAA;
+ sockaddrlen = sizeof(struct sockaddr_in6);
+ }
+ dnsresult->result.addr.addresslen = sockaddrlen;
+ dnsresult->result.addr.address = malloc(sockaddrlen);
+ if(!dnsresult->result.addr.address) {
+ iolog_trigger(IOLOG_ERROR, "Failed to allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+ goto dnsengine_cares_callback_finally;
+ }
+ void *target = (host->h_addrtype == AF_INET ? ((void *) &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr) : ((void *) &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr));
+ memcpy(target, *h_addr, host->h_length);
+
+ if(host->h_addrtype == AF_INET) {
+ char str[INET_ADDRSTRLEN];
+ inet_ntop( AF_INET, &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr, str, INET_ADDRSTRLEN );
+ iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
+ } else {
+ char str[INET6_ADDRSTRLEN];
+ inet_ntop( AF_INET6, &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN );
+ iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
+ }
+
+ dnsresult->next = iodns->result;
+ iodns->result = dnsresult;
+ }
+
+ } else if((iodns->type & IODNS_REVERSE)) {
+ struct IODNSResult *dnsresult = malloc(sizeof(*dnsresult));
+ if(!dnsresult) {
+ iolog_trigger(IOLOG_ERROR, "Failed to allocate memory for IODNSResult in %s:%d", __FILE__, __LINE__);
+ goto dnsengine_cares_callback_finally;
+ }
+
+ dnsresult->type = IODNS_RECORD_PTR;
+ dnsresult->result.host = strdup(host->h_name);
+ if(!dnsresult->result.host) {
+ iolog_trigger(IOLOG_ERROR, "Failed to duplicate h_name string for IODNSResult in %s:%d", __FILE__, __LINE__);
+ goto dnsengine_cares_callback_finally;
+ }
+
+ dnsresult->next = iodns->result;
+ iodns->result = dnsresult;
+ }
+
+ query->query_successful++;
+ }
+ }
+ dnsengine_cares_callback_finally:
+ if(query->query_count <= 0) {
+ if(iodns) {
+ iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
+ iodns_event_callback(iodns, (query->query_successful ? IODNSEVENT_SUCCESS : IODNSEVENT_FAILED));
+ }
+ free(query);
+ }
+}