Author: brane
Date: Fri Jul 25 11:04:38 2025
New Revision: 1927464

Log:
Add an asyncrhonous connection creation API. This is likely to be the most
common use of the asyncrhonous resolver.

* serf.h
  (serf_connection_created_t): Callback type for serf_connection_create_async.
  (serf_connection_create_async): New.

* src/outgoing.c
  (async_create_baton): New; baton for asyncrhonous address resolution.
  (async_conn_create): New; callback for same, actually creates the connection.
  (serf_connection_create_async): Implement.

* test/test_util.c
  (async_reolved_baton, address_resolved): Removed.
  (conn_created): New callback.
  (use_new_async_connection): Use serf_connection_create_async.

Modified:
   serf/trunk/serf.h
   serf/trunk/src/outgoing.c
   serf/trunk/test/test_util.c

Modified: serf/trunk/serf.h
==============================================================================
--- serf/trunk/serf.h   Fri Jul 25 10:20:01 2025        (r1927463)
+++ serf/trunk/serf.h   Fri Jul 25 11:04:38 2025        (r1927464)
@@ -546,7 +546,7 @@ apr_status_t serf_connection_create3(
  * The @a ctx and @a resolved_baton arguments are the same that were passed
  * to serf_address_resolve_async().
  *
- * @a status contains the result of the address resolution. If it is notably
+ * @a status contains the result of the address resolution. If it is not
  * @c APR_SUCCESS, then @a host_address is invalid and should be ignored.
  *
  * The resolved @a host_address is ephemeral, allocated iun @a pool and lives
@@ -592,6 +592,56 @@ apr_status_t serf_address_resolve_async(
     apr_pool_t *pool);
 
 
+/**
+ * Notification callback when a connection hae been created.
+ *
+ * The @a ctx and @a created_baton arguments are the same that were passed
+ * to serf_connection_create_async().
+ *
+ * @a status contains the result of the connection creation. If it is not
+ * @c APR_SUCCESS, then @a conn is invalid and should be ignored.
+ *
+ * The created @a conn is allocated in the pool that was passed to
+ * serf_connection_create_async(); this is @b not the same as @a pool.
+ *
+ * All temporary allocations should be made in @a pool.
+ *
+ * @since New in 1.4.
+ */
+/* FIXME: EXPERIMENTAL */
+typedef void (*serf_connection_created_t)(
+    serf_context_t *ctx,
+    void *created_baton,
+    serf_connection_t *conn,
+    apr_status_t status,
+    apr_pool_t *pool);
+
+/**
+ * Asyncchronously create a new connection associated with
+ * the @a ctx serf context.
+ *
+ * Like serf_connection_create3() with @a host_address set to @c NULL,
+ * except that address resolution is performed asynchronously, similarly to
+ * serf_address_resolve_async().
+ *
+ * The @a created callback with @a created_baton is called when the connection
+ * is created but before it is opened.
+ *
+ * @since New in 1.4.
+ */
+/* FIXME: EXPERIMENTAL */
+apr_status_t serf_connection_create_async(
+    serf_context_t *ctx,
+    apr_uri_t host_info,
+    serf_connection_created_t created,
+    void *created_baton,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    apr_pool_t *pool);
+
+
 typedef apr_status_t (*serf_accept_client_t)(
     serf_context_t *ctx,
     serf_listener_t *l,

Modified: serf/trunk/src/outgoing.c
==============================================================================
--- serf/trunk/src/outgoing.c   Fri Jul 25 10:20:01 2025        (r1927463)
+++ serf/trunk/src/outgoing.c   Fri Jul 25 11:04:38 2025        (r1927464)
@@ -1362,6 +1362,78 @@ apr_status_t serf_connection_create3(
     return status;
 }
 
+
+struct async_create_baton
+{
+    apr_uri_t host_info;
+    serf_connection_created_t created;
+    void *created_baton;
+    serf_connection_setup_t setup;
+    void *setup_baton;
+    serf_connection_closed_t closed;
+    void *closed_baton;
+    apr_pool_t *conn_pool;
+};
+
+static void async_conn_create(serf_context_t *ctx,
+                              void *resolved_baton,
+                              apr_sockaddr_t *host_address,
+                              apr_status_t status,
+                              apr_pool_t *scratch_pool)
+{
+    struct async_create_baton *const baton = resolved_baton;
+    serf_connection_t *conn = NULL;
+
+    if (status == APR_SUCCESS)
+    {
+        status = apr_sockaddr_info_copy(&host_address, host_address,
+                                        baton->conn_pool);
+        if (status == APR_SUCCESS) {
+            status = serf_connection_create3(&conn, ctx,
+                                             baton->host_info,
+                                             host_address,
+                                             baton->setup, baton->setup_baton,
+                                             baton->closed, 
baton->closed_baton,
+                                             baton->conn_pool);
+        }
+    }
+
+    baton->created(ctx, baton->created_baton, conn, status, scratch_pool);
+}
+
+apr_status_t serf_connection_create_async(
+    serf_context_t *ctx,
+    apr_uri_t host_info,
+    serf_connection_created_t created,
+    void *created_baton,
+    serf_connection_setup_t setup,
+    void *setup_baton,
+    serf_connection_closed_t closed,
+    void *closed_baton,
+    apr_pool_t *pool)
+{
+    apr_pool_t *scratch_pool;
+    apr_status_t status;
+
+    struct async_create_baton *const baton = apr_palloc(pool, sizeof(*baton));
+    baton->host_info = host_info;
+    baton->created = created;
+    baton->created_baton = created_baton;
+    baton->setup = setup;
+    baton->setup_baton = setup_baton;
+    baton->closed = closed;
+    baton->closed_baton = closed_baton;
+    baton->conn_pool = pool;
+
+    apr_pool_create(&scratch_pool, pool);
+    status = serf_address_resolve_async(ctx, host_info,
+                                        async_conn_create, baton,
+                                        scratch_pool);
+    apr_pool_destroy(scratch_pool);
+    return status;
+}
+
+
 apr_status_t serf_connection_reset(
     serf_connection_t *conn)
 {

Modified: serf/trunk/test/test_util.c
==============================================================================
--- serf/trunk/test/test_util.c Fri Jul 25 10:20:01 2025        (r1927463)
+++ serf/trunk/test/test_util.c Fri Jul 25 11:04:38 2025        (r1927464)
@@ -142,44 +142,22 @@ apr_status_t use_new_connection(test_bat
     return status;
 }
 
-struct async_reolved_baton
+static void conn_created(serf_context_t *ctx,
+                         void *resolved_baton,
+                         serf_connection_t *conn,
+                         apr_status_t status,
+                         apr_pool_t *unused_scratch_pool)
 {
-    test_baton_t *tb;
-    apr_uri_t url;
-};
-
-static void address_resolved(serf_context_t *ctx,
-                             void *resolved_baton,
-                             apr_sockaddr_t *host_address,
-                             apr_status_t status,
-                             apr_pool_t *unused_scratch_pool)
-{
-    struct async_reolved_baton *baton = resolved_baton;
-    test_baton_t *tb = baton->tb;
-    serf_connection_t *conn;
-    apr_pool_t *conn_pool = tb->pool;
+    test_baton_t *tb = resolved_baton;
 
     if (tb->context != ctx)
         REPORT_TEST_SUITE_ERROR();
 
     if (status == APR_SUCCESS)
     {
-        status = apr_sockaddr_info_copy(&host_address, host_address, 
conn_pool);
-        if (status == APR_SUCCESS)
-            status = serf_connection_create3(&conn, ctx,
-                                             baton->url,
-                                             host_address,
-                                             tb->conn_setup,
-                                             tb,
-                                             default_closed_connection,
-                                             tb,
-                                             conn_pool);
-        if (status == APR_SUCCESS)
-        {
-            tb->connection = conn;
-            apr_pool_cleanup_register(conn_pool, tb->connection, cleanup_conn,
-                                      apr_pool_cleanup_null);
-        }
+        tb->connection = conn;
+        apr_pool_cleanup_register(tb->pool, tb->connection, cleanup_conn,
+                                  apr_pool_cleanup_null);
     }
 
     tb->user_status = status;
@@ -190,7 +168,6 @@ apr_status_t use_new_async_connection(te
 {
     apr_uri_t url;
     apr_status_t status;
-    struct async_reolved_baton *baton;
 
     if (tb->connection)
         cleanup_conn(tb->connection);
@@ -200,12 +177,12 @@ apr_status_t use_new_async_connection(te
     if (status != APR_SUCCESS)
         return status;
 
-    baton = apr_palloc(pool, sizeof(*baton));
-    baton->tb = tb;
-    baton->url = url;
     tb->user_status = APR_SUCCESS;
-    return serf_address_resolve_async(tb->context, url,
-                                      address_resolved, baton, pool);
+    return serf_connection_create_async(tb->context, url,
+                                        conn_created, tb,
+                                        tb->conn_setup, tb,
+                                        default_closed_connection, tb,
+                                        tb->pool);
 }
 
 static test_baton_t *initTestCtx(CuTest *tc, apr_pool_t *pool)

Reply via email to