From a8a4abb2ae97c9a42db0cb82c7f1c508b01d75f3 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Wed, 15 Jun 2022 02:20:49 -0400 Subject: [PATCH] vtls: make curl_global_sslset thread-safe .. and update some docs to explain curl_global_* is now thread-safe. Follow-up to 23af112 which made curl_global_init/cleanup thread-safe. Closes https://github.com/curl/curl/pull/9016 --- docs/libcurl/curl_global_cleanup.3 | 6 +++++- docs/libcurl/curl_global_init.3 | 2 +- docs/libcurl/curl_global_sslset.3 | 6 +++++- docs/libcurl/libcurl-thread.3 | 6 +++++- docs/libcurl/libcurl.3 | 29 ++++++++++++++++------------- lib/easy.c | 17 +++++++++++++++++ lib/vtls/vtls.c | 10 ++++++---- lib/vtls/vtls.h | 3 +++ 8 files changed, 58 insertions(+), 21 deletions(-) diff --git a/docs/libcurl/curl_global_cleanup.3 b/docs/libcurl/curl_global_cleanup.3 index 1c2dd9cfea..983f03422f 100644 --- a/docs/libcurl/curl_global_cleanup.3 +++ b/docs/libcurl/curl_global_cleanup.3 @@ -36,7 +36,11 @@ This function releases resources acquired by \fIcurl_global_init(3)\fP. You should call \fIcurl_global_cleanup(3)\fP once for each call you make to \fIcurl_global_init(3)\fP, after you are done using libcurl. -\fBThis function is not thread safe.\fP You must not call it when any other +This function is thread-safe since libcurl 7.84.0 if +\fIcurl_version_info(3)\fP has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other thread in the program (i.e. a thread sharing the same memory) is running. This does not just mean no other thread that is using libcurl. Because \fIcurl_global_cleanup(3)\fP calls functions of other libraries that are diff --git a/docs/libcurl/curl_global_init.3 b/docs/libcurl/curl_global_init.3 index de0251e2c1..fd33ccd99d 100644 --- a/docs/libcurl/curl_global_init.3 +++ b/docs/libcurl/curl_global_init.3 @@ -47,7 +47,7 @@ value unless you are familiar with it and mean to control internal operations of libcurl. This function is thread-safe since libcurl 7.84.0 if -\fIcurl_version_info(3)\fP has CURL_VERSION_THREADSAFE feature bit set +\fIcurl_version_info(3)\fP has the CURL_VERSION_THREADSAFE feature bit set (most platforms). If this is not thread-safe, you must not call this function when any other diff --git a/docs/libcurl/curl_global_sslset.3 b/docs/libcurl/curl_global_sslset.3 index c0ebd5a492..1b99f96dab 100644 --- a/docs/libcurl/curl_global_sslset.3 +++ b/docs/libcurl/curl_global_sslset.3 @@ -81,7 +81,11 @@ function again to try to select a different backend. The SSL backend can be set only once. If it has already been set, a subsequent attempt to change it will result in a \fBCURLSSLSET_TOO_LATE\fP. -\fBThis function is not thread safe.\fP You must not call it when any other +This function is thread-safe since libcurl 7.84.0 if +\fIcurl_version_info(3)\fP has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If this is not thread-safe, you must not call this function when any other thread in the program (i.e. a thread sharing the same memory) is running. This does not just mean no other thread that is using libcurl. .SH EXAMPLE diff --git a/docs/libcurl/libcurl-thread.3 b/docs/libcurl/libcurl-thread.3 index 3e316a853f..1b00b90d10 100644 --- a/docs/libcurl/libcurl-thread.3 +++ b/docs/libcurl/libcurl-thread.3 @@ -94,7 +94,11 @@ problem reports on *BSD (at least in the past, they may be working fine these days). Some operating systems that are known to have solid and working thread support are Linux, Solaris and Windows. .IP "curl_global_* functions" -These functions are not thread safe. If you are using libcurl with multiple +These functions are thread-safe since libcurl 7.84.0 if +\fIcurl_version_info(3)\fP has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). + +If these functions are not thread-safe and you are using libcurl with multiple threads it is especially important that before use you call \fIcurl_global_init(3)\fP or \fIcurl_global_init_mem(3)\fP to explicitly initialize the library and its dependents, rather than rely on the "lazy" diff --git a/docs/libcurl/libcurl.3 b/docs/libcurl/libcurl.3 index d5ba1f5c2f..5f3e264daa 100644 --- a/docs/libcurl/libcurl.3 +++ b/docs/libcurl/libcurl.3 @@ -154,28 +154,31 @@ that library that describes the SSL protocol. allocate resources (e.g. the memory for the GNU TLS tree mentioned above), so the companion function \fIcurl_global_cleanup(3)\fP releases them. -The basic rule for constructing a program that uses libcurl is this: Call +The global constant functions are thread-safe since libcurl 7.84.0 if +\fIcurl_version_info(3)\fP has the CURL_VERSION_THREADSAFE feature bit set +(most platforms). Read \fIlibcurl-thread(3)\fP for thread safety guidelines. + +If the global constant functions are \fInot thread safe\fP, then you must +not call them when any other thread in the program is running. It +is not good enough that no other thread is using libcurl at the time, +because these functions internally call similar functions of other +libraries, and those functions are similarly thread-unsafe. You cannot +generally know what these libraries are, or whether other threads are +using them. + +If the global constant functions are \fInot thread safe\fP, then the basic rule +for constructing a program that uses libcurl is this: Call \fIcurl_global_init(3)\fP, with a \fICURL_GLOBAL_ALL\fP argument, immediately after the program starts, while it is still only one thread and before it uses libcurl at all. Call \fIcurl_global_cleanup(3)\fP immediately before the program exits, when the program is again only one thread and after its last use of libcurl. -You can call both of these multiple times, as long as all calls meet -these requirements and the number of calls to each is the same. - It is not actually required that the functions be called at the beginning and end of the program -- that is just usually the easiest way to do it. -It \fIis\fP required that the functions be called when no other thread -in the program is running. -These global constant functions are \fInot thread safe\fP, so you must -not call them when any other thread in the program is running. It -is not good enough that no other thread is using libcurl at the time, -because these functions internally call similar functions of other -libraries, and those functions are similarly thread-unsafe. You cannot -generally know what these libraries are, or whether other threads are -using them. +You can call both of these multiple times, as long as all calls meet +these requirements and the number of calls to each is the same. The global constant situation merits special consideration when the code you are writing to use libcurl is not the main program, but rather diff --git a/lib/easy.c b/lib/easy.c index 71751e35a5..aa642015fe 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -315,6 +315,23 @@ void curl_global_cleanup(void) global_init_unlock(); } +/* + * curl_global_sslset() globally initializes the SSL backend to use. + */ +CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + CURLsslset rc; + + global_init_lock(); + + rc = Curl_init_sslset_nolock(id, name, avail); + + global_init_unlock(); + + return rc; +} + /* * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index aa3dda3d25..faa1b51417 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1456,8 +1456,10 @@ static int multissl_setup(const struct Curl_ssl *backend) return 0; } -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) +/* This function is used to select the SSL backend to use. It is called by + curl_global_sslset (easy.c) which uses the global init lock. */ +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) { int i; @@ -1486,8 +1488,8 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, } #else /* USE_SSL */ -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) { (void)id; (void)name; diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 08c7ac31da..e1e58f4215 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -125,6 +125,9 @@ struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); bool Curl_none_false_start(void); bool Curl_ssl_tls13_ciphersuites(void); +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + #include "openssl.h" /* OpenSSL versions */ #include "gtls.h" /* GnuTLS versions */ #include "nssg.h" /* NSS versions */ -- 2.47.3