Author: brane
Date: Sat Jul 26 20:11:05 2025
New Revision: 1927485
Log:
In the Unbound resolver, finally convert the results to apr_sockaddr_t.
* src/resolve.c:
- Do not include <arpa/inet.h> or <netinet/in.h>, they're no longer used.
- Declare APR_WANT_MEMFUNC and APR_WANT_BYTEFUNC throught <apr_want.h>.
- Include <apr_strings.h>.
- Update the top-level todo list.
(INET_ADDRSTRLEN, INET6_ADDRSTRLEN): Define if not defined.
(resolve_result): Remove the 'err' member, it's no longer needed.
(unbound_resolve_task): Add 'host_port_str', copied from apr_uri_t.
(resolve_convert): New; convert struct ub_result to apr_sockaddr_t.
(resolve_finalize): Call resolve_convert and calculate the final status.
(resolve_callback): Remove resolve debug logging, now in resolve_convert.
Fix the interpretation of the return value from apr_atomic_dec32().
(resolve_address_async): Initialize unbound_resolve_task::host_port_str.
Fix the interpretation of the return value from apr_atomic_dec32().
(resolve) [thread-pool resolver]: Use APR's address stringifier in the
debug logging code.
Modified:
serf/trunk/src/resolve.c
Modified: serf/trunk/src/resolve.c
==============================================================================
--- serf/trunk/src/resolve.c Sat Jul 26 18:45:01 2025 (r1927484)
+++ serf/trunk/src/resolve.c Sat Jul 26 20:11:05 2025 (r1927485)
@@ -21,18 +21,14 @@
#include <apr.h>
#include <apr_version.h>
-/* Include the headers needed for inet_ntop and related structs.
- On Windows, we'll always get <Winsock2.h> from <apr.h>. */
-#if APR_HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#if APR_HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
+#define APR_WANT_BYTEFUNC
+#define APR_WANT_MEMFUNC
+#include <apr_want.h>
#include <apr_errno.h>
#include <apr_pools.h>
#include <apr_atomic.h>
+#include <apr_strings.h>
#include <apr_network_io.h>
#include <apr_thread_mutex.h>
#include <apr_thread_pool.h>
@@ -51,6 +47,13 @@
#include "serf.h"
#include "serf_private.h"
+/* Stringified address lengths. */
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN sizeof("255.255.255.255")
+#endif
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+#endif
#define HAVE_ASYNC_RESOLVER (SERF_HAVE_ASYNC_RESOLVER || APR_HAS_THREADS)
@@ -60,8 +63,8 @@
* - Wake the poll/select in serf_context_run() when new resolve
* results are available.
*
- * TODO for Unbound:
- * - Convert unbound results to apr_sockaddr_t.
+ * - Unbound: Detect when the "hostname" is actually a stringified IP address.
+ * The resolver doesn't handle that, so we have to short-circuit that case.
*/
@@ -277,7 +280,6 @@ typedef struct unbound_resolve_task reso
struct resolve_result
{
- int err;
apr_status_t status;
struct ub_result* ub_result;
resolve_task_t *task;
@@ -287,6 +289,7 @@ struct resolve_result
struct unbound_resolve_task
{
serf_context_t *ctx;
+ char *host_port_str;
apr_port_t host_port;
/* There can be one or two pending results, depending on whether
@@ -299,15 +302,126 @@ struct unbound_resolve_task
apr_pool_t *resolve_pool;
};
+static apr_status_t resolve_convert(apr_sockaddr_t **host_address,
+ apr_int32_t family,
+ const struct resolve_result *result)
+{
+ const struct unbound_resolve_task *const task = result->task;
+ const struct ub_result *const ub_result = result->ub_result;
+ apr_pool_t *const resolve_pool = task->resolve_pool;
+ apr_status_t status = result->status;
+
+ if (status == APR_SUCCESS)
+ {
+ char *hostname = apr_pstrdup(resolve_pool, (ub_result->canonname
+ ? ub_result->canonname
+ : ub_result->qname));
+ apr_socklen_t salen;
+ int ipaddr_len;
+ int addr_str_len;
+ int i;
+
+ if (family == APR_INET) {
+ salen = sizeof(struct sockaddr_in);
+ ipaddr_len = sizeof(struct in_addr);
+ addr_str_len = INET_ADDRSTRLEN;
+ }
+#if APR_HAVE_IPV6
+ else {
+ salen = sizeof(struct sockaddr_in6);
+ ipaddr_len = sizeof(struct in6_addr);
+ addr_str_len = INET6_ADDRSTRLEN;
+ }
+#endif
+
+ /* Check that all result sizes are correct. */
+ for (i = 0; ub_result->data[i]; ++i)
+ {
+ if (ub_result->len[i] != ipaddr_len) {
+ /* TODO: Error callback */
+ serf__log(LOGLVL_ERROR, LOGCOMP_CONN, __FILE__,
+ task->ctx->config,
+ "unbound resolve: [%s] invalid address: "
+ " length %d, expected %d\n",
+ result->qtype, ub_result->len[i], ipaddr_len);
+ status = APR_EINVAL;
+ goto cleanup;
+ }
+ }
+
+ for (i = 0; ub_result->data[i]; ++i)
+ {
+ apr_sockaddr_t *addr = apr_palloc(resolve_pool, sizeof(*addr));
+ addr->pool = resolve_pool;
+ addr->hostname = hostname;
+ addr->servname = task->host_port_str;
+ addr->port = task->host_port;
+ addr->family = family;
+ addr->salen = salen;
+ addr->ipaddr_len = ipaddr_len;
+ addr->addr_str_len = addr_str_len;
+ addr->next = *host_address;
+
+ memset(&addr->sa, 0, sizeof(addr->sa));
+ if (family == APR_INET) {
+ addr->ipaddr_ptr = &addr->sa.sin.sin_addr.s_addr;
+ addr->sa.sin.sin_family = APR_INET;
+ addr->sa.sin.sin_port = htons(addr->port);
+ }
+#if APR_HAVE_IPV6
+ else {
+ addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr.s6_addr;
+ addr->sa.sin6.sin6_family = APR_INET6;
+ addr->sa.sin6.sin6_port = htons(addr->port);
+ }
+#endif
+ memcpy(addr->ipaddr_ptr, ub_result->data[i], ipaddr_len);
+ *host_address = addr;
+
+ if (serf__log_enabled(LOGLVL_DEBUG, LOGCOMP_CONN,
+ task->ctx->config)) {
+ char buf[INET6_ADDRSTRLEN];
+ if (!apr_sockaddr_ip_getbuf(buf, sizeof(buf), addr)) {
+ serf__log(LOGLVL_DEBUG, LOGCOMP_CONN,
+ __FILE__, task->ctx->config,
+ "unbound resolve: [%s] %s: %s\n",
+ result->qtype, addr->hostname, buf);
+ }
+ }
+ }
+ }
+
+ cleanup:
+ if (result->ub_result)
+ ub_resolve_free(result->ub_result);
+
+ return status;
+}
+
static void resolve_finalize(resolve_task_t *task)
{
- /* TODO: Convert ub_result to apr_sockaddr_t */
- if (task->results[0].ub_result)
- ub_resolve_free(task->results[0].ub_result);
- if (task->results[1].ub_result)
- ub_resolve_free(task->results[1].ub_result);
+ apr_sockaddr_t *host_address = NULL;
+ apr_status_t status, status6;
+
+ status = resolve_convert(&host_address, APR_INET, &task->results[0]);
+#if APR_HAVE_IPV6
+ status6 = resolve_convert(&host_address, APR_INET6, &task->results[1]);
+#else
+ status6 = APR_SUCCESS;
+#endif
- push_resolve_result(task->ctx, NULL, APR_EAFNOSUPPORT,
+ if (!host_address) {
+ if (status == APR_SUCCESS)
+ status = status6;
+ if (status == APR_SUCCESS)
+ status = APR_ENOENT;
+ }
+ else {
+ /* If we got a result, ee don't care if one of the resolves failed. */
+ status = APR_SUCCESS;
+ }
+
+ push_resolve_result(task->ctx, host_address, status,
task->resolved, task->resolved_baton,
task->resolve_pool);
}
@@ -369,33 +483,11 @@ static void resolve_callback(void* baton
}
}
- resolve_result->err = err;
resolve_result->status = status;
resolve_result->ub_result = ub_result;
- if (status == APR_SUCCESS
- && serf__log_enabled(LOGLVL_DEBUG, LOGCOMP_CONN, task->ctx->config))
- {
- char buf[INET6_ADDRSTRLEN];
- const socklen_t len = sizeof(buf);
- int i;
-
- for (i = 0; ub_result->data && ub_result->data[i]; ++i) {
- const char *address = "(AF-unknown)";
-
- if (ub_result->len[i] == sizeof(struct in_addr))
- address = inet_ntop(AF_INET, ub_result->data[i], buf, len);
- else if (ub_result->len[i] == sizeof(struct in6_addr))
- address = inet_ntop(AF_INET6, ub_result->data[i], buf, len);
- serf__log(LOGLVL_DEBUG, LOGCOMP_CONN,
- __FILE__, task->ctx->config,
- "unbound resolve: [%s] %s: %s\n",
- resolve_result->qtype, ub_result->qname, address);
- }
- }
-
/* The last pending task combines and publishes the results. */
- if (apr_atomic_dec32(&task->pending_results) == 1)
+ if (apr_atomic_dec32(&task->pending_results) == 0)
resolve_finalize(task);
}
@@ -412,6 +504,7 @@ static apr_status_t resolve_address_asyn
int err4 = 0, err6 = 0;
task->ctx = ctx;
+ task->host_port_str = apr_pstrdup(resolve_pool, host_info.port_str);
task->host_port = host_info.port;
#if APR_HAVE_IPV6
@@ -419,7 +512,6 @@ static apr_status_t resolve_address_asyn
#else
task->pending_results = 1;
#endif
- task->results[0].err = task->results[1].err = 0;
task->results[0].status = task->results[1].status = APR_SUCCESS;
task->results[0].ub_result = task->results[1].ub_result = NULL;
task->results[0].task = task->results[1].task = task;
@@ -474,7 +566,7 @@ static apr_status_t resolve_address_asyn
/* If one of the tasks failed and the other has already completed,
we have to do the result processing here. Note that the Unbound
callbacks can be called synchronously from ub_resolve_async(). */
- if (pending_results == 1)
+ if (pending_results == 0)
resolve_finalize(task);
}
@@ -589,14 +681,11 @@ static void *APR_THREAD_FUNC resolve(apr
while (addr)
{
char buf[INET6_ADDRSTRLEN];
- const socklen_t len = sizeof(buf);
- const char *address = "(AF-unknown)";
-
- if (addr->family == APR_INET || addr->family == APR_INET6)
- address = inet_ntop(addr->family, addr->ipaddr_ptr, buf, len);
- serf__log(LOGLVL_DEBUG, LOGCOMP_CONN,
- __FILE__, task->ctx->config,
- "apr async resolve: %s: %s\n", addr->hostname, address);
+ if (!apr_sockaddr_ip_getbuf(buf, sizeof(buf), addr)) {
+ serf__log(LOGLVL_DEBUG, LOGCOMP_CONN,
+ __FILE__, task->ctx->config,
+ "apr async resolve: %s: %s\n", addr->hostname, buf);
+ }
addr = addr->next;
}
}