From 9ffd41173574deb4a6b157b453e11b0c9296c199 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 25 Sep 2023 17:08:41 +0200 Subject: [PATCH] curl_multi_get_handles: get easy handles from a multi handle Closes #11750 --- docs/libcurl/Makefile.inc | 1 + docs/libcurl/curl_multi_get_handles.3 | 73 +++++++++++++++++++++++++++ include/curl/multi.h | 11 ++++ lib/conncache.c | 1 + lib/doh.c | 1 + lib/multi.c | 18 +++++++ lib/urldata.h | 6 ++- libcurl.def | 1 + scripts/singleuse.pl | 1 + tests/data/test1135 | 1 + 10 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 docs/libcurl/curl_multi_get_handles.3 diff --git a/docs/libcurl/Makefile.inc b/docs/libcurl/Makefile.inc index e7e8280124c8..1f3b1e2ff884 100644 --- a/docs/libcurl/Makefile.inc +++ b/docs/libcurl/Makefile.inc @@ -73,6 +73,7 @@ man_MANS = \ curl_multi_assign.3 \ curl_multi_cleanup.3 \ curl_multi_fdset.3 \ + curl_multi_get_handles.3 \ curl_multi_info_read.3 \ curl_multi_init.3 \ curl_multi_perform.3 \ diff --git a/docs/libcurl/curl_multi_get_handles.3 b/docs/libcurl/curl_multi_get_handles.3 new file mode 100644 index 000000000000..3999bbe1bab2 --- /dev/null +++ b/docs/libcurl/curl_multi_get_handles.3 @@ -0,0 +1,73 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" * SPDX-License-Identifier: curl +.\" * +.\" ************************************************************************** +.TH curl_multi_get_handles 3 "28 August 2023" "libcurl" "libcurl" +.SH NAME +curl_multi_get_handles - returns all added easy handles +.SH SYNOPSIS +.nf +#include + +CURL **curl_multi_get_handles(CURLM *multi_handle); +.fi +.SH DESCRIPTION +Returns an array with pointers to all added easy handles. The end of the list +is marked with a NULL pointer. + +Even if there is not a single easy handle added, this still returns an array +but with only a single NULL pointer entry. + +The returned array contains all the handles that are present at the time of +the call. As soon as a handle has been removed from or a handle has been added +to the multi handle after the handle array was returned, the two data points +are out of sync. + +The order of the easy handles within the array is not guaranteed. + +The returned array must be freed with a call to \fIcurl_free(3)\fP after use. +.SH EXAMPLE +.nf + /* init a multi stack */ + multi_handle = curl_multi_init(); + + /* add a transfer */ + curl_multi_add_handle(multi_handle, http_handle); + + /* extract all added handles */ + CURL **list = curl_multi_get_handles(multi_handle); + + if(list) { + /* remove all added handles */ + for(i = 0; list[i]; i++) { + curl_multi_remove_handle(multi_handle, list[i]); + } + curl_free(list); + } +.fi +.SH AVAILABILITY +Added in 8.4.0 +.SH RETURN VALUE +Returns NULL on failure. Otherwise it returns a pointer to an allocated array. +.SH "SEE ALSO" +.BR curl_multi_cleanup "(3)," curl_multi_init "(3), " +.BR curl_multi_add_handle "(3), " curl_multi_remove_handle "(3) " diff --git a/include/curl/multi.h b/include/curl/multi.h index 13b55b780792..e79b48ff32ac 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -426,6 +426,17 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); +/* + * Name: curl_multi_get_handles() + * + * Desc: Returns an allocated array holding all handles currently added to + * the multi handle. Marks the final entry with a NULL pointer. If + * there is no easy handle added to the multi handle, this function + * returns an array with the first entry as a NULL pointer. + * + * Returns: NULL on failure, otherwise a CURL **array pointer + */ +CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle); /* * Name: curl_push_callback diff --git a/lib/conncache.c b/lib/conncache.c index a21409c13f1f..93d87686c8e2 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -107,6 +107,7 @@ int Curl_conncache_init(struct conncache *connc, int size) connc->closure_handle = curl_easy_init(); if(!connc->closure_handle) return 1; /* bad */ + connc->closure_handle->internal = true; Curl_hash_init(&connc->hash, size, Curl_hash_str, Curl_str_key_compare, free_bundle_hash_entry); diff --git a/lib/doh.c b/lib/doh.c index 6f99a061c33b..bb0c89ec6d86 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -242,6 +242,7 @@ static CURLcode dohprobe(struct Curl_easy *data, /* pass in the struct pointer via a local variable to please coverity and the gcc typecheck helpers */ struct dynbuf *resp = &p->serverdoh; + doh->internal = true; ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https"); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); diff --git a/lib/multi.c b/lib/multi.c index 19a950a80205..15b998865e27 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -3788,3 +3788,21 @@ unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi) DEBUGASSERT(multi); return multi->max_concurrent_streams; } + +struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi) +{ + struct Curl_easy **a = malloc(sizeof(struct Curl_easy *) * + (multi->num_easy + 1)); + if(a) { + int i = 0; + struct Curl_easy *e = multi->easyp; + while(e) { + DEBUGASSERT(i < multi->num_easy); + if(!e->internal) + a[i++] = e; + e = e->next; + } + a[i] = NULL; /* last entry is a NULL */ + } + return a; +} diff --git a/lib/urldata.h b/lib/urldata.h index 82f0f18b1b92..989caeeb8dfc 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1950,7 +1950,7 @@ struct Curl_easy { other using the same cache. For easier tracking in log output. This may wrap around after LONG_MAX to 0 again, so it - has no uniqueness guarantuee for very large processings. */ + has no uniqueness guarantee for very large processings. */ curl_off_t id; /* first, two fields for the linked list of these */ @@ -2013,6 +2013,10 @@ struct Curl_easy { #ifdef USE_HYPER struct hyptransfer hyp; #endif + + /* internal: true if this easy handle was created for internal use and the + user does not have ownership of the handle. */ + bool internal; }; #define LIBCURL_NAME "libcurl" diff --git a/libcurl.def b/libcurl.def index 1de609e80dfd..c6c96063a11b 100644 --- a/libcurl.def +++ b/libcurl.def @@ -51,6 +51,7 @@ curl_multi_add_handle curl_multi_assign curl_multi_cleanup curl_multi_fdset +curl_multi_get_handles curl_multi_info_read curl_multi_init curl_multi_perform diff --git a/scripts/singleuse.pl b/scripts/singleuse.pl index 7b0b09964703..b8a57f8d8d85 100755 --- a/scripts/singleuse.pl +++ b/scripts/singleuse.pl @@ -96,6 +96,7 @@ 'curl_multi_assign' => 'API', 'curl_multi_cleanup' => 'API', 'curl_multi_fdset' => 'API', + 'curl_multi_get_handles' => 'API', 'curl_multi_info_read' => 'API', 'curl_multi_init' => 'API', 'curl_multi_perform' => 'API', diff --git a/tests/data/test1135 b/tests/data/test1135 index 0f055e9bc17b..17191feba3a0 100644 --- a/tests/data/test1135 +++ b/tests/data/test1135 @@ -106,6 +106,7 @@ curl_multi_socket_all curl_multi_timeout curl_multi_setopt curl_multi_assign +curl_multi_get_handles curl_pushheader_bynum curl_pushheader_byname curl_easy_option_by_name