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;
         }
     }

Reply via email to