public inbox for gwml@vger.gnuweeb.org
 help / color / mirror / Atom feed
From: Ahmad Gani <reyuki@gnuweeb.org>
To: Ammar Faizi <ammarfaizi2@gnuweeb.org>
Cc: Ahmad Gani <reyuki@gnuweeb.org>,
	Alviro Iskandar Setiawan <alviro.iskandar@gnuweeb.org>,
	GNU/Weeb Mailing List <gwml@vger.gnuweeb.org>
Subject: [PATCH gwproxy v3 6/6] dnslookup: Make gw_ares_getaddrinfo asynchronous
Date: Tue,  5 Aug 2025 20:04:48 +0700	[thread overview]
Message-ID: <20250805130451.146549-7-reyuki@gnuweeb.org> (raw)
In-Reply-To: <20250805130451.146549-1-reyuki@gnuweeb.org>

The previous gw_ares_getaddrinfo version is blocking and no different
with glibc's getaddrinfo, this changes introduce asynchronous version of
gw_ares_getaddrinfo function.

Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
 src/gwproxy/dnslookup.c | 367 ++++++++++++++++++++++++++++------------
 src/gwproxy/dnslookup.h |  99 ++++++++---
 src/gwproxy/dnsparser.c |  14 +-
 3 files changed, 337 insertions(+), 143 deletions(-)

diff --git a/src/gwproxy/dnslookup.c b/src/gwproxy/dnslookup.c
index de286fb5ab14..91d38b4e64d2 100644
--- a/src/gwproxy/dnslookup.c
+++ b/src/gwproxy/dnslookup.c
@@ -6,48 +6,45 @@
 #include <gwproxy/dnslookup.h>
 #include <gwproxy/dnsparser.h>
 #include <gwproxy/syscall.h>
-#include <sys/syscall.h>
+#include <sys/epoll.h>
 #include <unistd.h>
 
-static int resolve_name(int sockfd, const char *name, uint16_t type, uint16_t nport,
-	struct gw_ares_addrinfo *result, struct gw_addrinfo_node **tail)
+int gw_ares_process_event(gw_ares_channel_t *channel)
 {
-	uint8_t send_buff[UDP_MSG_LIMIT];
 	uint8_t recv_buff[UDP_MSG_LIMIT];
-	gwdns_query_pkt *query_pkt;
+	struct gw_ares_request *req;
 	gwdns_answ_data raw_answ;
-	gwdns_question_part q;
-	ssize_t buff_len;
+	socklen_t addrlen;
 	int ret;
 
-	q.domain = name;
-	q.type = type;
-	q.dst_buffer = send_buff;
-	q.dst_len = UDP_MSG_LIMIT;
-	buff_len = construct_question(&q);
-	if (buff_len < 0) {
-		/*
-		 * I'm confident that 512 bytes is more than sufficient
-		 * to construct single dns query packet.
-		 */
-		assert(buff_len != -ENOBUFS);
-		ret = GW_ARES_EINVAL;
-		return ret;
-	}
-	query_pkt = (void *)send_buff;
-
-	ret = __sys_send(sockfd, send_buff, buff_len, MSG_NOSIGNAL);
+	addrlen = sizeof(*channel->addr);
+	ret = __sys_recvfrom(channel->sockfd, recv_buff, UDP_MSG_LIMIT,
+				MSG_NOSIGNAL, &channel->addr->sa, &addrlen);
 	if (ret < 0) {
-		ret = GW_ARES_INTERNAL_ERR;
+		/* GW_ARES_WAITING is unused for now. */
+		if (ret == -EAGAIN)
+			ret = GW_ARES_WAITING;
+		else
+			ret = GW_ARES_INTERNAL_ERR;
 		return ret;
 	}
 
-	ret = __sys_recv(sockfd, recv_buff, UDP_MSG_LIMIT, MSG_NOSIGNAL);
-	if (ret < 0) {
-		ret = GW_ARES_INTERNAL_ERR;
-		return ret;
+	if (ret < 2)
+		return GW_ARES_EINVAL;
+
+	printf("%d bytes received\n", ret);
+	req = NULL;
+	int idx;
+	for (idx = 0; idx < channel->req_nr; idx++) {
+		if (!memcmp(&channel->reqs[idx]->txid, recv_buff, 2)) {
+			req = channel->reqs[idx];
+			break;
+		}
 	}
 
+	if (!req)
+		return GW_ARES_NOENT;
+
 	/* 
 	 * TODO(reyuki): even though it's unlikely,
 	 * but what todo when the connection is closed?
@@ -55,7 +52,8 @@ static int resolve_name(int sockfd, const char *name, uint16_t type, uint16_t np
 	 */
 	assert(ret);
 
-	ret = serialize_answ(query_pkt->hdr.id, recv_buff, ret, &raw_answ);
+	memset(&raw_answ, 0, sizeof(raw_answ));
+	ret = serialize_answ(req->txid, recv_buff, ret, &raw_answ);
 	if (ret) {
 		/*
 		 * TODO(reyuki): the reason of failure can vary,
@@ -63,13 +61,20 @@ static int resolve_name(int sockfd, const char *name, uint16_t type, uint16_t np
 		 * short recv, but this is UDP packet, retry from send?
 		 * or just drop the request?
 		 */
+		assert(ret == -ENODATA);
 	}
-	assert(!ret);
 
-	/* TODO(reyuki): hints->ai_family is used to filter results */
-	for (size_t i = 0; i < raw_answ.hdr.ancount; i++) {
-		gwdns_serialized_answ *answ = raw_answ.rr_answ[i];
-		struct gw_addrinfo_node *new_node = malloc(sizeof(*new_node));
+	printf("ancount=%u\n", raw_answ.hdr.ancount);
+
+	size_t i;
+	for (i = 0; i < raw_answ.hdr.ancount; i++) {
+		struct gw_addrinfo_node *new_node;
+		gwdns_serialized_answ *answ;
+		struct sockaddr_in6 *i6;
+		struct sockaddr_in *i4;
+
+		answ = raw_answ.rr_answ[i];
+		new_node = malloc(sizeof(*new_node));
 		if (!new_node) {
 			ret = GW_ARES_ENOMEM;
 			goto exit_free;
@@ -77,119 +82,193 @@ static int resolve_name(int sockfd, const char *name, uint16_t type, uint16_t np
 		new_node->ai_next = NULL;
 
 		if (answ->rr_type == TYPE_AAAA) {
+			i6 = &new_node->ai_addr.i6;
 			new_node->ai_family = AF_INET6;
-			new_node->ai_addrlen = sizeof(new_node->ai_addr.i6);
-			new_node->ai_addr.i6.sin6_port = nport;
-			new_node->ai_addr.i6.sin6_family = AF_INET6;
+			new_node->ai_addrlen = sizeof(i6);
+			i6->sin6_port = req->dst_port;
+			i6->sin6_family = AF_INET6;
 			/*
 			 * no overflow.
 			 * it's guaranteed to be true by serialize_answ function
 			 */
-			assert(sizeof(new_node->ai_addr.i6.sin6_addr) == answ->rdlength);
-			memcpy(&new_node->ai_addr.i6.sin6_addr, answ->rdata, answ->rdlength);
+			assert(sizeof(i6->sin6_addr) == answ->rdlength);
+			memcpy(&i6->sin6_addr, answ->rdata, answ->rdlength);
 		} else {
+			i4 = &new_node->ai_addr.i4;
 			new_node->ai_family = AF_INET;
-			new_node->ai_addrlen = sizeof(new_node->ai_addr.i4);
-			new_node->ai_addr.i4.sin_port = nport;
-			new_node->ai_addr.i4.sin_family = AF_INET;
+			new_node->ai_addrlen = sizeof(i4);
+			i4->sin_port = req->dst_port;
+			i4->sin_family = AF_INET;
 			/*
 			 * no overflow.
 			 * it's guaranteed to be true by serialize_answ function
 			 */
-			assert(sizeof(new_node->ai_addr.i4.sin_addr) == answ->rdlength);
-			memcpy(&new_node->ai_addr.i4.sin_addr, answ->rdata, answ->rdlength);
+			assert(sizeof(i4->sin_addr) == answ->rdlength);
+			memcpy(&i4->sin_addr, answ->rdata, answ->rdlength);
 			new_node->ai_ttl = answ->ttl;
 		}
 
-		if (!*tail)
-			result->nodes = new_node;
+		if (!req->tail)
+			req->results->nodes = new_node;
 		else
-			(*tail)->ai_next = new_node;
-		*tail = new_node;
+			req->tail->ai_next = new_node;
+		req->tail = new_node;
 	}
 
 	ret = GW_ARES_SUCCESS;
 exit_free:
 	free_serialize_answ(&raw_answ);
+	req->refcnt--;
+	assert(req->refcnt >= 0);
+	if (!req->refcnt) {
+		channel->getaddrinfo_cb(
+			req->callback_args, GW_ARES_SUCCESS, req->results
+		);
+		free(req);
+		channel->req_nr--;
+		req = channel->reqs[channel->req_nr];
+		channel->reqs[idx] = req;
+		channel->reqs[channel->req_nr] = NULL;
+	}
 	return ret;
 }
 
+static int resolve_name(gw_ares_channel_t *channel, const char *name,
+			uint16_t type, uint16_t txid)
+{
+	uint8_t send_buff[UDP_MSG_LIMIT];
+	gwdns_question_part q;
+	ssize_t buff_len;
+	int ret;
+
+	q.domain = name;
+	q.type = type;
+	q.txid = txid;
+	q.dst_buffer = send_buff;
+	q.dst_len = UDP_MSG_LIMIT;
+	buff_len = construct_question(&q);
+	if (buff_len < 0) {
+		/*
+		 * I'm confident that 512 bytes is more than sufficient
+		 * to construct single dns query packet.
+		 */
+		assert(buff_len != -ENOBUFS);
+		ret = GW_ARES_EINVAL;
+		return ret;
+	}
+
+	ret = __sys_sendto(
+		channel->sockfd, send_buff, buff_len, MSG_NOSIGNAL,
+		&channel->addr->sa, channel->addrlen
+	);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int resize_reqs(gw_ares_channel_t *channel)
+{
+	struct gw_ares_request **ptr;
+	int new_cap;
+
+	new_cap = channel->req_cap * 2;
+	ptr = realloc(channel->reqs, new_cap);
+	if (!ptr)
+		return -ENOMEM;
+
+	memset(ptr[channel->req_nr], 0, channel->req_nr * sizeof(*channel->reqs));
+	channel->reqs = ptr;
+	channel->req_cap = new_cap;
+
+	return 0;
+}
+
 void gw_ares_getaddrinfo(gw_ares_channel_t *channel,
 			const char *name, const char *service,
-			const struct gw_ares_addrinfo_hints *hints,
-			gw_ares_addrinfo_callback callback, void *arg)
+			const struct gw_ares_addrinfo_hints *hints, void *arg)
 {
-	struct gw_ares_addrinfo *result;
-	struct gw_addrinfo_node *tail;
-	struct gwp_sockaddr *addr;
-	socklen_t addrlen;
-	int ret, sockfd;
+	struct gw_ares_addrinfo *results;
+	struct gw_ares_request *req;
 	uint16_t nport;
 	uint8_t mask;
+	int ret;
+
+	if (channel->req_nr == channel->req_cap) {
+		ret = resize_reqs(channel);
+		if (ret) {
+			ret = GW_ARES_ENOMEM;
+			goto error;
+		}
+	}
+	assert(channel->req_nr < channel->req_cap);
+
+	req = malloc(sizeof(*req));
+	if (!req) {
+		ret = GW_ARES_ENOMEM;
+		goto error;
+	}
+	channel->reqs[channel->req_nr] = req;
+	channel->req_nr++;
+
+	req->tail = NULL;
+	req->txid = (uint16_t)rand();
 
 	switch (hints->ai_family) {
 		case AF_UNSPEC:
 			mask = I6_BIT | I4_BIT;
+			req->refcnt = 2;
 			break;
 		case AF_INET:
+			req->refcnt = 1;
 			mask = I4_BIT;
 			break;
 		case AF_INET6:
+			req->refcnt = 1;
 			mask = I6_BIT;
 			break;
 		default:
 			ret = GW_ARES_EINVAL;
-			goto error;
+			goto error_free_req;
 	}
 
 	nport = (uint16_t)atoi(service);
 	if (!nport) {
 		ret = GW_ARES_EINVAL;
-		goto error;
+		goto error_free_req;
 	}
 	nport = htons(nport);
 
-	result = malloc(sizeof(*result));
-	if (!result) {
+	results = malloc(sizeof(*results));
+	if (!results) {
 		ret = GW_ARES_ENOMEM;
-		goto error;
-	}
-
-	addr = &channel->servers[0];
-	sockfd = __sys_socket(addr->sa.sa_family, SOCK_DGRAM, 0);
-	if (sockfd < 0) {
-		ret = GW_ARES_INTERNAL_ERR;
-		goto error_free;
+		goto error_free_req;
 	}
 
-	addrlen = addr->sa.sa_family == AF_INET ? sizeof(addr->i4) : sizeof(addr->i6);
-	ret = __sys_connect(sockfd, &addr->sa, addrlen);
-	if (ret < 0) {
-		ret = GW_ARES_INTERNAL_ERR;
-		goto error_close;
-	}
+	req->dst_port = nport;
+	req->results = results;
 
-	tail = NULL;
 	if (IS_I6(mask)) {
-		ret = resolve_name(sockfd, name, TYPE_AAAA, nport, result, &tail);
+		ret = resolve_name(channel, name, TYPE_AAAA, req->txid);
 		if (ret)
-			goto error_close;
+			goto error_free_all;
 	}
 
 	if (IS_I4(mask)) {
-		ret = resolve_name(sockfd, name, TYPE_A, nport, result, &tail);
+		ret = resolve_name(channel, name, TYPE_A, req->txid);
 		if (ret)
-			goto error_close;
+			goto error_free_all;
 	}
 
-	callback(arg, GW_ARES_SUCCESS, result);
 	return;
-error_close:
-	__sys_close(sockfd);
-error_free:
-	free(result);
+error_free_all:
+	free(results);
+error_free_req:
+	free(req);
+	channel->req_nr--;
+	channel->reqs[channel->req_nr] = NULL;
 error:
-	callback(arg, ret, result);
+	channel->getaddrinfo_cb(arg, ret, results);
 }
 
 void gw_ares_freeaddrinfo(struct gw_ares_addrinfo *ai)
@@ -218,68 +297,136 @@ int gw_ares_init(gw_ares_channel_t **channel, struct gw_ares_options *opts)
 
 	*channel = c;
 	c->nr_server = opts->nr_server;
+
+	ret = -ENOMEM;
+
+	c->reqs = calloc(DEFAULT_REQ_CAP, sizeof(*c->reqs));
+	if (!c->reqs)
+		goto error_free_c;
+
 	c->servers = malloc(c->nr_server * sizeof(*c->servers));
-	if (!c->servers) {
-		free(c);
-		return -ENOMEM;
-	}
+	if (!c->servers)
+		goto error_free_reqs;
+
 	/*
-	 * TODO(reyuki): validate flags and
-	 * for now use it to control recursion desired (RD) bit?
+	 * TODO(reyuki): validate flags
+	 * For now flags is unused but it may be used to control
+	 * recursion desired (RD) bit and other things in the future.
 	 */
 	c->flags = opts->flags;
-	for (int i = 0; i < c->nr_server; i++) {
-		ret = convert_str_to_ssaddr(opts->servers[i], &c->servers[i], DEFAULT_DOMAIN_PORT);
-		if (ret) {
-			free(c->servers);
-			free(c);
-			return ret;
-		}
+	int i;
+	for (i = 0; i < c->nr_server; i++) {
+		ret = convert_str_to_ssaddr(
+			opts->servers[i], &c->servers[i], DEFAULT_DOMAIN_PORT
+		);
+		if (ret)
+			goto error_free_all;
 	}
 
+	ret = __sys_socket(c->servers[0].sa.sa_family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+	if (ret < 0)
+		goto error_free_all;
+
+	opts->sockstate_cb(opts->sockstate_data, ret);
+	c->req_cap = DEFAULT_REQ_CAP;
+	c->req_nr = 0;
+	c->getaddrinfo_cb = opts->getaddrinfo_cb;
+	c->sockfd = ret;
+	c->addr = &c->servers[0];
+	c->addrlen = c->addr->sa.sa_family == AF_INET ?
+			sizeof(c->addr->i4) : sizeof(c->addr->i6);
+
 	return 0;
+error_free_all:
+	free(c->servers);
+error_free_reqs:
+	free(c->reqs);
+error_free_c:
+	free(c);
+	return ret;
 }
 
 void gw_ares_deinit(gw_ares_channel_t *channel)
 {
 	free(channel->servers);
+	free(channel->reqs);
 	free(channel);
 }
 
-static void gw_ares_cb(void *arg, int status, struct gw_ares_addrinfo *result)
+static void sockstate_cb(void *data, int socket)
+{
+	int epfd = *(int *)data;
+	struct epoll_event ev = {
+		.events = EPOLLIN
+	};
+
+	__sys_epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &ev);
+}
+
+static void getaddrinfo_cb(void *arg, int status, struct gw_ares_addrinfo *result)
 {
 	struct gw_addrinfo_node *node;
 	char buf[FULL_ADDRSTRLEN];
 
 	(void)arg;
 
+	if (status)
+		printf("status=%d\n", status);
 	assert(!status);
 	node = result->nodes;
 	while (node) {
 		int r = convert_ssaddr_to_str(buf, &node->ai_addr);
 		assert(!r);
-		printf("%s: %s\n", node->ai_family == AF_INET6 ? "IPv6" : "IPv4", buf);
+		printf(
+			"%s: %s\n",
+			node->ai_family == AF_INET6 ? "IPv6" : "IPv4", buf
+		);
 		node = node->ai_next;
 	}
+
 	gw_ares_freeaddrinfo(result);
 }
 
 int main(void)
 {
+	struct gw_ares_addrinfo_hints hints;
+	struct gw_ares_options opts;
 	gw_ares_channel_t *channel;
-	struct gw_ares_addrinfo_hints hints = {
-		.ai_family = AF_UNSPEC
-	};
+	struct epoll_event ev;
+	int ret, epfd;
+
 	const char *servers[] = {"1.1.1.1", "8.8.8.8"};
-	struct gw_ares_options opts = {
-		.flags = 0,
-		.nr_server = 1,
-		.servers = servers
-	};
-	int ret;
+
+	epfd = __sys_epoll_create1(0);
+	if (epfd < 0)
+		return -EXIT_FAILURE;
+
+	opts.flags = 0;
+	opts.nr_server = 1;
+	opts.servers = servers;
+	opts.sockstate_data = &epfd;
+	opts.sockstate_cb = sockstate_cb;
+	opts.getaddrinfo_cb = getaddrinfo_cb;
 	ret = gw_ares_init(&channel, &opts);
 	if (ret)
 		return -EXIT_FAILURE;
-	gw_ares_getaddrinfo(channel, "google.com", "80", &hints, gw_ares_cb, NULL);
+
+	hints.ai_family = AF_UNSPEC;
+	gw_ares_getaddrinfo(channel, "google.com", "80", &hints, NULL);
+	gw_ares_getaddrinfo(channel, "facebook.com", "80", &hints, NULL);
+	gw_ares_getaddrinfo(channel, "github.com", "80", &hints, NULL);
+
+	while (true) {
+		if (!channel->req_nr)
+			break;
+
+		ret = __sys_epoll_wait(epfd, &ev, 1024, -1);
+		if (ret < 0)
+			return -EXIT_FAILURE;
+
+		if (ev.events & EPOLLIN)
+			gw_ares_process_event(channel);
+	}
+
 	gw_ares_deinit(channel);
 }
diff --git a/src/gwproxy/dnslookup.h b/src/gwproxy/dnslookup.h
index a4ed02cab5f1..a98ed6cff23c 100644
--- a/src/gwproxy/dnslookup.h
+++ b/src/gwproxy/dnslookup.h
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <gwproxy/net.h>
 
+#define DEFAULT_REQ_CAP 50
 #define DEFAULT_DOMAIN_PORT 53
 #define I6_BIT (1u << 0)
 #define I4_BIT (1u << 1)
@@ -18,31 +19,35 @@ enum {
 	 * internal error can be interpreted as system call failure, 
 	 * however, the cause of it can be vary.
 	 */
-	GW_ARES_INTERNAL_ERR	= 3
+	GW_ARES_INTERNAL_ERR	= 3,
+	GW_ARES_WAITING		= 4,
+	GW_ARES_NOENT		= 5
 };
 
-struct gw_ares_options {
-	int		flags;
-	int		nr_server;
+typedef void (*gw_ares_sockstate_cb)(void *data, int socket);
 
-	/* 
-	 * the string format is ip:port, the ip may be encapsulated with square
-	 * brackets ([]), and must be if using IPv6.
-	 */
-	const char	**servers;
+struct gw_ares_addrinfo {
+	struct gw_addrinfo_node *nodes;
+	char			*name;
 };
 
-struct gw_ares_channeldata {
+/*
+ * result is only initialized if status == GW_ARES_SUCCESS.
+ */
+typedef void (*gw_ares_addrinfo_cb)(void *arg, int status,
+					struct gw_ares_addrinfo *result);
+
+struct gw_ares_options {
 	int			flags;
 	int			nr_server;
-	/* currently only index 0 is used, and others are ignored. */
-	struct gwp_sockaddr	*servers;
-};
-
-typedef struct gw_ares_channeldata gw_ares_channel_t;
-
-struct gw_ares_addrinfo_hints {
-	int ai_family;
+	/* 
+	 * the string format is ip:port, the ip may be encapsulated with square
+	 * brackets ([]), and must be if using IPv6.
+	 */
+	const char		**servers;
+	gw_ares_sockstate_cb	sockstate_cb;
+	gw_ares_addrinfo_cb	getaddrinfo_cb;
+	void			*sockstate_data;
 };
 
 /*
@@ -59,16 +64,36 @@ struct gw_addrinfo_node {
 	struct gw_addrinfo_node	*ai_next;
 };
 
-struct gw_ares_addrinfo {
-	struct gw_addrinfo_node *nodes;
-	char			*name;
+struct gw_ares_request {
+	int			refcnt;
+	uint16_t		dst_port;
+	uint16_t		txid;
+	struct gw_ares_addrinfo *results;
+	struct gw_addrinfo_node *tail;
+	void			*callback_args;
 };
 
-/*
- * result is only initialized if status == GW_ARES_SUCCESS.
- */
-typedef void (*gw_ares_addrinfo_callback)(void *arg, int status,
-					struct gw_ares_addrinfo *result);
+struct gw_ares_channeldata {
+	int			flags;
+	int			nr_server;
+	/* currently only index 0 is used, and others are ignored. */
+	struct gwp_sockaddr	*servers;
+	gw_ares_addrinfo_cb	getaddrinfo_cb;
+
+	int			sockfd;
+	struct gwp_sockaddr	*addr;
+	socklen_t		addrlen;
+
+	struct gw_ares_request	**reqs;
+	int			req_nr;
+	int			req_cap;
+};
+
+typedef struct gw_ares_channeldata gw_ares_channel_t;
+
+struct gw_ares_addrinfo_hints {
+	int ai_family;
+};
 
 /* 
  * Initiate a host query by name and service
@@ -86,8 +111,7 @@ typedef void (*gw_ares_addrinfo_callback)(void *arg, int status,
  */
 void gw_ares_getaddrinfo(gw_ares_channel_t *channel,
 			const char *name, const char *service,
-			const struct gw_ares_addrinfo_hints *hints,
-			gw_ares_addrinfo_callback callback, void *arg);
+			const struct gw_ares_addrinfo_hints *hints, void *arg);
 
 /*
  * Free the resources allocated by gw_ares_getaddrinfo.
@@ -115,4 +139,23 @@ void gw_ares_freeaddrinfo(struct gw_ares_addrinfo *ai);
  * @return zero on success and negative integer on error
  */
 int gw_ares_init(gw_ares_channel_t **channel, struct gw_ares_options *opts);
+
+/*
+ * Free the resources allocated by gw_ares_init.
+ * 
+ * @param channel
+ */
 void gw_ares_deinit(gw_ares_channel_t *channel);
+
+/*
+ * Process event
+ * 
+ * Description:
+ * the gw_ares_process_event function performing socket-related operation,
+ * you MUST call this when certain I/O in DNS socket file descriptor
+ * is ready to use.
+ * 
+ * @param channel
+ * @return zero on success and negative integer on error
+ */
+int gw_ares_process_event(gw_ares_channel_t *channel);
diff --git a/src/gwproxy/dnsparser.c b/src/gwproxy/dnsparser.c
index 2d8af1da2893..442ea5558174 100644
--- a/src/gwproxy/dnsparser.c
+++ b/src/gwproxy/dnsparser.c
@@ -122,7 +122,8 @@ int serialize_answ(uint16_t txid, uint8_t *in, size_t in_len, gwdns_answ_data *o
 	if (!out->rr_answ)
 		return -ENOMEM;
 
-	for (size_t i = 0; i < hdr->ancount; i++) {
+	size_t i;
+	for (i = 0; i < hdr->ancount; i++) {
 		uint16_t is_compressed, rdlength;
 		gwdns_serialized_answ *item = malloc(sizeof(gwdns_serialized_answ));
 		if (!item) {
@@ -211,7 +212,7 @@ int serialize_answ(uint16_t txid, uint8_t *in, size_t in_len, gwdns_answ_data *o
 
 	return 0;
 exit_free:
-	for (size_t i = 0; i < out->hdr.ancount; i++) {
+	for (i = 0; i < out->hdr.ancount; i++) {
 		free(out->rr_answ[i]->rdata);
 		free(out->rr_answ[i]);
 	}
@@ -221,7 +222,8 @@ exit_free:
 
 void free_serialize_answ(gwdns_answ_data *answ)
 {
-	for (size_t i = 0; i < answ->hdr.ancount; i++) {
+	size_t i;
+	for (i = 0; i < answ->hdr.ancount; i++) {
 		free(answ->rr_answ[i]->rdata);
 		free(answ->rr_answ[i]);
 	}
@@ -300,7 +302,8 @@ void test_parse_ipv4(void)
 
 	memcpy(&txid, recv_pkt, 2);
 	assert(!serialize_answ(txid, recv_pkt, sizeof(recv_pkt), &d));
-	for (size_t i = 0; i < d.hdr.ancount; i++) {
+	size_t i;
+	for (i = 0; i < d.hdr.ancount; i++) {
 		struct gwp_sockaddr gs;
 		gwdns_serialized_answ *answ;
 		char buff[FULL_ADDRSTRLEN];
@@ -367,7 +370,8 @@ void test_parse_ipv6(void)
 
 	ret = serialize_answ(txid, recv_pkt, sizeof(recv_pkt), &d);
 	assert(!ret);
-	for (size_t i = 0; i < d.hdr.ancount; i++) {
+	size_t i;
+	for (i = 0; i < d.hdr.ancount; i++) {
 		struct gwp_sockaddr gs;
 		gwdns_serialized_answ *answ;
 		char buff[FULL_ADDRSTRLEN];
-- 
Ahmad Gani


  parent reply	other threads:[~2025-08-05 13:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-05 13:04 [PATCH gwproxy v3 0/6] Initial work for DNS lookup implementation Ahmad Gani
2025-08-05 13:04 ` [PATCH gwproxy v3 1/6] dnslookup: Split common functionality and struct into net.h and net.c Ahmad Gani
2025-08-05 13:04 ` [PATCH gwproxy v3 2/6] dnslookup: Add a new parameter default_port Ahmad Gani
2025-08-06  3:25   ` Ammar Faizi
2025-08-05 13:04 ` [PATCH gwproxy v3 3/6] dnslookup: Allow only port string number Ahmad Gani
2025-08-05 13:04 ` [PATCH gwproxy v3 4/6] dnslookup: Initial work for implementation of C-ares-like getaddrinfo function Ahmad Gani
2025-08-05 13:04 ` [PATCH gwproxy v3 5/6] dnsparser: Transaction id creation is delegated to caller Ahmad Gani
2025-08-05 13:04 ` Ahmad Gani [this message]
2025-08-06  3:31 ` [PATCH gwproxy v3 0/6] Initial work for DNS lookup implementation Ammar Faizi
2025-08-06  3:43   ` Ahmad Gani
  -- strict thread matches above, loose matches on Subject: below --
2025-08-05 12:40 Ahmad Gani
2025-08-05 12:40 ` [PATCH gwproxy v3 6/6] dnslookup: Make gw_ares_getaddrinfo asynchronous Ahmad Gani

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250805130451.146549-7-reyuki@gnuweeb.org \
    --to=reyuki@gnuweeb.org \
    --cc=alviro.iskandar@gnuweeb.org \
    --cc=ammarfaizi2@gnuweeb.org \
    --cc=gwml@vger.gnuweeb.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox