<commit_before>#include <uwsgi.h>
#include <ares.h>
#include <arpa/nameser.h>

extern struct uwsgi_server uwsgi;

/*

	--cares-server = [strlist]
	--cares-timeout = <int>
	--cares-cache = <cache_name>
	--cares-cache-ttl = <cache_name>

	${dns[HTTP_HOST]}
	${dns[0:HTTP_HOST]}
	${dns[1:HTTP_HOST]}
	${dns[r:HTTP_HOST]}

	${dns_txt[r:HTTP_HOST]}

	${dns_ptr[r:REMOTE_ADDR]}

	${dns[a:HTTP_HOST]}
*/

static struct uwsgi_cares {
	int initialized;
	int timeout;
	char *cache;
	int ttl;
} ucares;

struct uwsgi_cares_query {
	int cb_done;
	int ok;
	struct uwsgi_buffer *ub;
};

void dns_a_cb(void *arg, int status, int timeouts, unsigned char *buf, int len) {
	struct uwsgi_cares_query *ucq = (struct uwsgi_cares_query *) arg;
	ucq->cb_done = 1;
	if (status != ARES_SUCCESS) return;

	struct ares_addrttl attl[30];
	int ttl = 30;

	int ret = ares_parse_a_reply(buf, len, NULL, attl, &ttl);
	if (ret != ARES_SUCCESS) return;
	if (!inet_ntop(AF_INET, &attl[0].ipaddr, ucq->ub->buf, ucq->ub->len)) {
               	uwsgi_error("[uwsgi-cares] inet_ntop()");
		return;
	}
	ucq->ub->pos = strlen(ucq->ub->buf);
	// TODO cache the result ?

	// ok
	ucq->ok = 1;
}

static char *dns_get_a(char *name, uint16_t name_len, uint16_t *ip_len) {
	char *result = NULL;
	ares_channel channel;
	ares_socket_t socks[ARES_GETSOCK_MAXNUM];

	int ret = ares_init(&channel);
	if (ret) {
		uwsgi_log("[uwsgi-cares] error: %s\n", ares_strerror(ret));
		return NULL;
	}

	struct uwsgi_cares_query ucq;
	memset(&ucq, 0, sizeof(struct uwsgi_cares_query));
	ucq.ub = uwsgi_buffer_new(INET_ADDRSTRLEN);

	char *domain_name = NULL;
	char *port = memchr(name, ':', name_len);
	if (port) {
		domain_name = uwsgi_concat2n(name, port - name, "", 0);
	}
	else {	
		domain_name = uwsgi_concat2n(name, name_len, "", 0);
	}
	ares_query(channel, domain_name, ns_c_in, ns_t_a, dns_a_cb, &ucq);
	free(domain_name);
	
	for(;;) {
		int bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);

		int i;
		for(i=0;i<ARES_GETSOCK_MAXNUM;i++) {

			if(ARES_GETSOCK_READABLE(bitmask, i)) {
				int ret = uwsgi.wait_read_hook(socks[i], ucares.timeout);
        			if (ret <= 0) goto end;
				ares_process_fd(channel, socks[i], ARES_SOCKET_BAD);
				if (ucq.cb_done) goto end;
				break;
			}

			if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
				int ret = uwsgi.wait_write_hook(socks[i], ucares.timeout);
        			if (ret <= 0) goto end;
				ares_process_fd(channel, ARES_SOCKET_BAD, socks[i]);
				if (ucq.cb_done) goto end;
				break;
			}
		}
	}

end:

	if (ucq.cb_done && ucq.ok) {
		if (port) {
			if (uwsgi_buffer_append(ucq.ub, port, name_len - (port-name))) goto end2;
			uwsgi_log("%.*s\n", ucq.ub->pos, ucq.ub->buf);<commit_msg>removed debug<commit_after>#include <uwsgi.h>
#include <ares.h>
#include <arpa/nameser.h>

extern struct uwsgi_server uwsgi;

/*

	--cares-server = [strlist]
	--cares-timeout = <int>
	--cares-cache = <cache_name>
	--cares-cache-ttl = <cache_name>

	${dns[HTTP_HOST]}
	${dns[0:HTTP_HOST]}
	${dns[1:HTTP_HOST]}
	${dns[r:HTTP_HOST]}

	${dns_txt[r:HTTP_HOST]}

	${dns_ptr[r:REMOTE_ADDR]}

	${dns[a:HTTP_HOST]}
*/

static struct uwsgi_cares {
	int initialized;
	int timeout;
	char *cache;
	int ttl;
} ucares;

struct uwsgi_cares_query {
	int cb_done;
	int ok;
	struct uwsgi_buffer *ub;
};

void dns_a_cb(void *arg, int status, int timeouts, unsigned char *buf, int len) {
	struct uwsgi_cares_query *ucq = (struct uwsgi_cares_query *) arg;
	ucq->cb_done = 1;
	if (status != ARES_SUCCESS) return;

	struct ares_addrttl attl[30];
	int ttl = 30;

	int ret = ares_parse_a_reply(buf, len, NULL, attl, &ttl);
	if (ret != ARES_SUCCESS) return;
	if (!inet_ntop(AF_INET, &attl[0].ipaddr, ucq->ub->buf, ucq->ub->len)) {
               	uwsgi_error("[uwsgi-cares] inet_ntop()");
		return;
	}
	ucq->ub->pos = strlen(ucq->ub->buf);
	// TODO cache the result ?

	// ok
	ucq->ok = 1;
}

static char *dns_get_a(char *name, uint16_t name_len, uint16_t *ip_len) {
	char *result = NULL;
	ares_channel channel;
	ares_socket_t socks[ARES_GETSOCK_MAXNUM];

	int ret = ares_init(&channel);
	if (ret) {
		uwsgi_log("[uwsgi-cares] error: %s\n", ares_strerror(ret));
		return NULL;
	}

	struct uwsgi_cares_query ucq;
	memset(&ucq, 0, sizeof(struct uwsgi_cares_query));
	ucq.ub = uwsgi_buffer_new(INET_ADDRSTRLEN);

	char *domain_name = NULL;
	char *port = memchr(name, ':', name_len);
	if (port) {
		domain_name = uwsgi_concat2n(name, port - name, "", 0);
	}
	else {	
		domain_name = uwsgi_concat2n(name, name_len, "", 0);
	}
	ares_query(channel, domain_name, ns_c_in, ns_t_a, dns_a_cb, &ucq);
	free(domain_name);
	
	for(;;) {
		int bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);

		int i;
		for(i=0;i<ARES_GETSOCK_MAXNUM;i++) {

			if(ARES_GETSOCK_READABLE(bitmask, i)) {
				int ret = uwsgi.wait_read_hook(socks[i], ucares.timeout);
        			if (ret <= 0) goto end;
				ares_process_fd(channel, socks[i], ARES_SOCKET_BAD);
				if (ucq.cb_done) goto end;
				break;
			}

			if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
				int ret = uwsgi.wait_write_hook(socks[i], ucares.timeout);
        			if (ret <= 0) goto end;
				ares_process_fd(channel, ARES_SOCKET_BAD, socks[i]);
				if (ucq.cb_done) goto end;
				break;
			}
		}
	}

end:

	if (ucq.cb_done && ucq.ok) {
		if (port) {
			if (uwsgi_buffer_append(ucq.ub, port, name_len - (port-name))) goto end2;
{'fraction_non_alphanumeric': 0.15915069522735814, 'fraction_numerical': 0.008267568583239383, 'mean_word_length': 4.088910133843212, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2377615', 'n_tokens_mistral': 2533, 'n_tokens_neox': 2363, 'n_words': 453}