diff --git a/CMakeLists.txt b/CMakeLists.txt index e21f1384f2c7..2c5ecccb97de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -724,9 +724,9 @@ if(APPLE) if(NOT CURL_USE_OPENSSL AND NOT CURL_USE_GNUTLS) message(FATAL_ERROR "Apple SecTrust is only supported with Openssl/GnuTLS") endif() - find_library(COREFOUNDATION_FRAMEWORK NAMES "Security") - mark_as_advanced(COREFOUNDATION_FRAMEWORK) - if(NOT COREFOUNDATION_FRAMEWORK) + find_library(SECURITY_FRAMEWORK NAMES "Security") + mark_as_advanced(SECURITY_FRAMEWORK) + if(NOT SECURITY_FRAMEWORK) message(FATAL_ERROR "Security framework not found") endif() list(APPEND CURL_LIBS "-framework Security") diff --git a/REUSE.toml b/REUSE.toml index c124e6d2d928..4395fb0d4e1a 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -15,7 +15,6 @@ SPDX-PackageDownloadLocation = "https://curl.se/" path = [ "docs/INSTALL", "docs/libcurl/symbols-in-versions", - "docs/MAIL-ETIQUETTE", "docs/options-in-versions", "docs/THANKS", "lib/libcurl.vers.in", diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index bc62da242f76..a00a02eb532b 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -477,6 +477,14 @@ Examples: which directory (typically) contains `include` and `lib` subdirectories. No ending slash or backslash is necessary. +## Dependency options (Apple frameworks) + +- `COREFOUNDATION_FRAMEWORK`: Absolute path to `CoreFoundation` framework. (for IPv6 non-c-ares, SecTrust, wolfSSL) +- `CORESERVICES_FRAMEWORK`: Absolute path to `CoreServices` framework. (for IPv6 non-c-ares, SecTrust) +- `FOUNDATION_FRAMEWORK`: Absolute path to `Foundation` framework. (for Rustls) +- `SECURITY_FRAMEWORK`: Absolute path to `Security` framework. (for Rustls, SecTrust, wolfSSL) +- `SYSTEMCONFIGURATION_FRAMEWORK`: Absolute path to `SystemConfiguration` framework. (for IPv6 non-c-ares) + ## Test tools - `APXS`: Default: `apxs` diff --git a/lib/conncache.c b/lib/conncache.c index 983224722a3b..d3072fb2aa63 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -235,22 +235,23 @@ void Curl_cpool_destroy(struct cpool *cpool) { if(cpool && cpool->initialised && cpool->idata) { struct connectdata *conn; - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx pipe_ctx; CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections", cpool->share ? "[SHARE] " : "", cpool->num_conn); /* Move all connections to the shutdown list */ - sigpipe_init(&pipe_st); + sigpipe_init(&pipe_ctx); CPOOL_LOCK(cpool, cpool->idata); conn = cpool_get_first(cpool); + if(conn) + sigpipe_apply(cpool->idata, &pipe_ctx); while(conn) { cpool_remove_conn(cpool, conn); - sigpipe_apply(cpool->idata, &pipe_st); cpool_discard_conn(cpool, cpool->idata, conn, FALSE); conn = cpool_get_first(cpool); } CPOOL_UNLOCK(cpool, cpool->idata); - sigpipe_restore(&pipe_st); + sigpipe_restore(&pipe_ctx); Curl_hash_destroy(&cpool->dest2bundle); } } diff --git a/lib/cshutdn.c b/lib/cshutdn.c index 84db4e717ca6..7de6c07b289e 100644 --- a/lib/cshutdn.c +++ b/lib/cshutdn.c @@ -176,13 +176,13 @@ static bool cshutdn_destroy_oldest(struct cshutdn *cshutdn, } if(e) { - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; conn = Curl_node_elem(e); Curl_node_remove(e); - sigpipe_init(&pipe_st); - sigpipe_apply(data, &pipe_st); + sigpipe_init(&sigpipe_ctx); + sigpipe_apply(data, &sigpipe_ctx); Curl_cshutdn_terminate(data, conn, FALSE); - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); return TRUE; } return FALSE; @@ -222,7 +222,8 @@ static CURLcode cshutdn_wait(struct cshutdn *cshutdn, } static void cshutdn_perform(struct cshutdn *cshutdn, - struct Curl_easy *data) + struct Curl_easy *data, + struct Curl_sigpipe_ctx *sigpipe_ctx) { struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list); struct Curl_llist_node *enext; @@ -235,6 +236,7 @@ static void cshutdn_perform(struct cshutdn *cshutdn, CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections", Curl_llist_count(&cshutdn->list)); + sigpipe_apply(data, sigpipe_ctx); while(e) { enext = Curl_node_next(e); conn = Curl_node_elem(e); @@ -263,20 +265,19 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn, { struct curltime started = *Curl_pgrs_now(data); struct Curl_llist_node *e; - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; DEBUGASSERT(cshutdn); DEBUGASSERT(data); CURL_TRC_M(data, "[SHUTDOWN] shutdown all"); - sigpipe_init(&pipe_st); - sigpipe_apply(data, &pipe_st); + sigpipe_init(&sigpipe_ctx); while(Curl_llist_head(&cshutdn->list)) { timediff_t spent_ms; int remain_ms; - cshutdn_perform(cshutdn, data); + cshutdn_perform(cshutdn, data, &sigpipe_ctx); if(!Curl_llist_head(&cshutdn->list)) { CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly"); @@ -308,7 +309,7 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn, } DEBUGASSERT(!Curl_llist_count(&cshutdn->list)); - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); } int Curl_cshutdn_init(struct cshutdn *cshutdn, @@ -418,38 +419,11 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn, conn->connection_id, Curl_llist_count(&cshutdn->list)); } -static void cshutdn_multi_socket(struct cshutdn *cshutdn, - struct Curl_easy *data, - curl_socket_t s) -{ - struct Curl_llist_node *e; - struct connectdata *conn; - bool done; - - DEBUGASSERT(cshutdn->multi->socket_cb); - e = Curl_llist_head(&cshutdn->list); - while(e) { - conn = Curl_node_elem(e); - if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) { - Curl_cshutdn_run_once(data, conn, &done); - if(done || cshutdn_update_ev(cshutdn, data, conn)) { - Curl_node_remove(e); - Curl_cshutdn_terminate(data, conn, FALSE); - } - break; - } - e = Curl_node_next(e); - } -} - void Curl_cshutdn_perform(struct cshutdn *cshutdn, struct Curl_easy *data, - curl_socket_t s) + struct Curl_sigpipe_ctx *sigpipe_ctx) { - if((s == CURL_SOCKET_TIMEOUT) || (!cshutdn->multi->socket_cb)) - cshutdn_perform(cshutdn, data); - else - cshutdn_multi_socket(cshutdn, data, s); + cshutdn_perform(cshutdn, data, sigpipe_ctx); } /* return fd_set info about the shutdown connections */ diff --git a/lib/cshutdn.h b/lib/cshutdn.h index 0a15d39f1cbd..79c95cca5917 100644 --- a/lib/cshutdn.h +++ b/lib/cshutdn.h @@ -30,6 +30,7 @@ struct curl_pollfds; struct Curl_waitfds; struct Curl_multi; struct Curl_share; +struct Curl_sigpipe_ctx; /* Run the shutdown of the connection once. * Will shortly attach/detach `data` to `conn` while doing so. @@ -97,10 +98,9 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn, fd_set *read_fd_set, fd_set *write_fd_set, int *maxfd); -/* Run shut down connections using socket. If socket is CURL_SOCKET_TIMEOUT, - * run maintenance on all connections. */ +/* Run maintenance on all connections. */ void Curl_cshutdn_perform(struct cshutdn *cshutdn, struct Curl_easy *data, - curl_socket_t s); + struct Curl_sigpipe_ctx *sigpipe_ctx); #endif /* HEADER_CURL_CSHUTDN_H */ diff --git a/lib/easy.c b/lib/easy.c index 4fa979c7d11a..51936660cee2 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -750,7 +750,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) struct Curl_multi *multi; CURLMcode mresult; CURLcode result = CURLE_OK; - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -807,8 +807,8 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) /* assign this after curl_multi_add_handle() */ data->multi_easy = multi; - sigpipe_init(&pipe_st); - sigpipe_apply(data, &pipe_st); + sigpipe_init(&sigpipe_ctx); + sigpipe_apply(data, &sigpipe_ctx); /* run the transfer */ result = events ? easy_events(multi) : easy_transfer(multi); @@ -817,7 +817,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) a failure here, room for future improvement! */ (void)curl_multi_remove_handle(multi, data); - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); /* The multi handle is kept alive, owned by the easy handle */ return result; @@ -851,10 +851,10 @@ void curl_easy_cleanup(CURL *ptr) { struct Curl_easy *data = ptr; if(GOOD_EASY_HANDLE(data)) { - SIGPIPE_VARIABLE(pipe_st); - sigpipe_ignore(data, &pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; + sigpipe_ignore(data, &sigpipe_ctx); Curl_close(&data); - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); } } @@ -1287,7 +1287,7 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, { CURLcode result; struct connectdata *c = NULL; - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; *n = 0; result = easy_connection(data, &c); @@ -1299,9 +1299,9 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, needs to be reattached */ Curl_attach_connection(data, c); - sigpipe_ignore(data, &pipe_st); + sigpipe_ignore(data, &sigpipe_ctx); result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n); - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); if(result && result != CURLE_AGAIN) return CURLE_SEND_ERROR; diff --git a/lib/multi.c b/lib/multi.c index 594c39aff846..39cf594c624e 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -2325,7 +2325,8 @@ static CURLMcode state_connect(struct Curl_multi *multi, } static CURLMcode multi_runsingle(struct Curl_multi *multi, - struct Curl_easy *data) + struct Curl_easy *data, + struct Curl_sigpipe_ctx *sigpipe_ctx) { struct Curl_message *msg = NULL; bool connected; @@ -2354,10 +2355,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_uint32_bset_remove(&multi->dirty, data->mid); if(data == multi->admin) { - Curl_cshutdn_perform(&multi->cshutdn, multi->admin, CURL_SOCKET_TIMEOUT); + Curl_cshutdn_perform(&multi->cshutdn, multi->admin, sigpipe_ctx); return CURLM_OK; } + sigpipe_apply(data, sigpipe_ctx); do { /* A "stream" here is a logical stream if the protocol can handle that (HTTP/2), or the full connection for older protocols */ @@ -2731,7 +2733,7 @@ static CURLMcode multi_perform(struct Curl_multi *multi, CURLMcode returncode = CURLM_OK; struct curltime start = *multi_now(multi); uint32_t mid; - SIGPIPE_VARIABLE(pipe_st); + struct Curl_sigpipe_ctx sigpipe_ctx; if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; @@ -2739,7 +2741,8 @@ static CURLMcode multi_perform(struct Curl_multi *multi, if(multi->in_ntfy_callback) return CURLM_RECURSIVE_API_CALL; - sigpipe_init(&pipe_st); + sigpipe_init(&sigpipe_ctx); + if(Curl_uint32_bset_first(&multi->process, &mid)) { CURL_TRC_M(multi->admin, "multi_perform(running=%u)", Curl_multi_xfers_running(multi)); @@ -2752,13 +2755,12 @@ static CURLMcode multi_perform(struct Curl_multi *multi, Curl_uint32_bset_remove(&multi->dirty, mid); continue; } - sigpipe_apply(data, &pipe_st); - mresult = multi_runsingle(multi, data); + mresult = multi_runsingle(multi, data, &sigpipe_ctx); if(mresult) returncode = mresult; } while(Curl_uint32_bset_next(&multi->process, mid, &mid)); } - sigpipe_restore(&pipe_st); + sigpipe_restore(&sigpipe_ctx); if(multi_ischanged(multi, TRUE)) process_pending_handles(multi); @@ -3015,22 +3017,15 @@ static CURLMcode add_next_timeout(const struct curltime *pnow, return CURLM_OK; } -struct multi_run_ctx { - struct Curl_multi *multi; - size_t run_xfers; - SIGPIPE_MEMBER(pipe_st); -}; - -static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc, +static void multi_mark_expired_as_dirty(struct Curl_multi *multi, const struct curltime *ts) { - struct Curl_multi *multi = mrc->multi; struct Curl_easy *data = NULL; struct Curl_tree *t = NULL; /* * The loop following here will go on as long as there are expire-times left - * to process (compared to mrc->now) in the splay and 'data' will be + * to process (compared to `ts`) in the splay and 'data' will be * re-assigned for every expired handle we deal with. */ while(1) { @@ -3057,12 +3052,14 @@ static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc, } } -static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc) +static CURLMcode multi_run_dirty(struct Curl_multi *multi, + struct Curl_sigpipe_ctx *sigpipe_ctx, + uint32_t *pnum) { - struct Curl_multi *multi = mrc->multi; CURLMcode mresult = CURLM_OK; uint32_t mid; + *pnum = 0; if(Curl_uint32_bset_first(&multi->dirty, &mid)) { do { struct Curl_easy *data = Curl_multi_get_easy(multi, mid); @@ -3075,10 +3072,9 @@ static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc) continue; } - mrc->run_xfers++; - sigpipe_apply(data, &mrc->pipe_st); + (*pnum)++; /* runsingle() clears the dirty mid */ - mresult = multi_runsingle(multi, data); + mresult = multi_runsingle(multi, data, sigpipe_ctx); if(CURLM_OK >= mresult) { /* reassess event handling of data */ @@ -3105,12 +3101,11 @@ static CURLMcode multi_socket(struct Curl_multi *multi, int *running_handles) { CURLMcode mresult = CURLM_OK; - struct multi_run_ctx mrc; + struct Curl_sigpipe_ctx pipe_ctx; + uint32_t run_xfers; (void)ev_bitmask; - memset(&mrc, 0, sizeof(mrc)); - mrc.multi = multi; - sigpipe_init(&mrc.pipe_st); + sigpipe_init(&pipe_ctx); if(checkall) { /* *perform() deals with running_handles on its own */ @@ -3136,23 +3131,23 @@ static CURLMcode multi_socket(struct Curl_multi *multi, memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts)); } - multi_mark_expired_as_dirty(&mrc, multi_now(multi)); - mresult = multi_run_dirty(&mrc); + multi_mark_expired_as_dirty(multi, multi_now(multi)); + mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers); if(mresult) goto out; - if(mrc.run_xfers) { + if(run_xfers) { /* Running transfers takes time. With a new timestamp, we might catch * other expires which are due now. Instead of telling the application * to set a 0 timeout and call us again, we run them here. * Do that only once or it might be unfair to transfers on other * sockets. */ - multi_mark_expired_as_dirty(&mrc, &multi->now); - mresult = multi_run_dirty(&mrc); + multi_mark_expired_as_dirty(multi, &multi->now); + mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers); } out: - sigpipe_restore(&mrc.pipe_st); + sigpipe_restore(&pipe_ctx); if(multi_ischanged(multi, TRUE)) process_pending_handles(multi); diff --git a/lib/sigpipe.h b/lib/sigpipe.h index 5d2c78a2713c..2fd211c51429 100644 --- a/lib/sigpipe.h +++ b/lib/sigpipe.h @@ -29,15 +29,12 @@ (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL)) #include -struct sigpipe_ignore { +struct Curl_sigpipe_ctx { struct sigaction old_pipe_act; BIT(no_signal); }; -#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x -#define SIGPIPE_MEMBER(x) struct sigpipe_ignore x - -static void sigpipe_init(struct sigpipe_ignore *ig) +static CURL_INLINE void sigpipe_init(struct Curl_sigpipe_ctx *ig) { memset(ig, 0, sizeof(*ig)); ig->no_signal = TRUE; @@ -48,8 +45,8 @@ static void sigpipe_init(struct sigpipe_ignore *ig) * internals, and then sigpipe_restore() will restore the situation when we * return from libcurl again. */ -static void sigpipe_ignore(struct Curl_easy *data, - struct sigpipe_ignore *ig) +static CURL_INLINE void sigpipe_ignore(struct Curl_easy *data, + struct Curl_sigpipe_ctx *ig) { /* get a local copy of no_signal because the Curl_easy might not be around when we restore */ @@ -70,17 +67,17 @@ static void sigpipe_ignore(struct Curl_easy *data, * and SIGPIPE handling. It MUST only be called after a corresponding * sigpipe_ignore() was used. */ -static void sigpipe_restore(struct sigpipe_ignore *ig) +static CURL_INLINE void sigpipe_restore(struct Curl_sigpipe_ctx *ig) { if(!ig->no_signal) /* restore the outside state */ sigaction(SIGPIPE, &ig->old_pipe_act, NULL); } -static void sigpipe_apply(struct Curl_easy *data, - struct sigpipe_ignore *ig) +static CURL_INLINE void sigpipe_apply(struct Curl_easy *data, + struct Curl_sigpipe_ctx *ig) { - if(data->set.no_signal != ig->no_signal) { + if(data && (data->set.no_signal != ig->no_signal)) { sigpipe_restore(ig); sigpipe_ignore(data, ig); } @@ -88,12 +85,15 @@ static void sigpipe_apply(struct Curl_easy *data, #else /* for systems without sigaction */ -#define sigpipe_ignore(x, y) Curl_nop_stmt -#define sigpipe_apply(x, y) Curl_nop_stmt -#define sigpipe_init(x) Curl_nop_stmt -#define sigpipe_restore(x) Curl_nop_stmt -#define SIGPIPE_VARIABLE(x) -#define SIGPIPE_MEMBER(x) bool x +#define sigpipe_ignore(x, y) do { (void)x; (void)y; } while(0) +#define sigpipe_apply(x, y) do { (void)x; (void)y; } while(0) +#define sigpipe_init(x) do { (void)x; } while(0) +#define sigpipe_restore(x) do { (void)x; } while(0) + +struct Curl_sigpipe_ctx { + bool dummy; +}; + #endif #endif /* HEADER_CURL_SIGPIPE_H */