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)