Last active
May 28, 2018 12:15
-
-
Save kkaefer/8cb9cd042ac3b78ca917481182cadb15 to your computer and use it in GitHub Desktop.
Load cURL dynamically at runtime to avoid CURL_OPENSSL_3 vs. CURL_OPENSSL_4 symbol version mismatches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <curl/curl.h> | |
// Dynamically load all cURL functions. Debian-derived systems upgraded the OpenSSL version linked | |
// to in https://salsa.debian.org/debian/curl/commit/95c94957bb7e89e36e78b995fed468c42f64d18d | |
// They state: | |
// Rename libcurl3 to libcurl4, because libcurl exposes an SSL_CTX via | |
// CURLOPT_SSL_CTX_FUNCTION, and this object changes incompatibly between | |
// openssl 1.0 and openssl 1.1. | |
// Since we are not accessing the underlying OpenSSL context, we don't care whether we're linking | |
// against libcurl3 or libcurl4; both use the ABI version 4 which hasn't changed since 2006 | |
// (see https://curl.haxx.se/libcurl/abi.html). In fact, cURL's ABI compatibility is very good as | |
// shown on https://abi-laboratory.pro/tracker/timeline/curl/ | |
// Therefore, we're dynamically loading the cURL symbols we need to avoid linking against versioned | |
// symbols. | |
#include <dlfcn.h> | |
namespace curl { | |
#define CURL_FUNCTIONS \ | |
X(global_init) \ | |
X(getdate) \ | |
X(easy_strerror) \ | |
X(easy_init) \ | |
X(easy_setopt) \ | |
X(easy_cleanup) \ | |
X(easy_getinfo) \ | |
X(easy_reset) \ | |
X(multi_init) \ | |
X(multi_add_handle) \ | |
X(multi_remove_handle) \ | |
X(multi_cleanup) \ | |
X(multi_info_read) \ | |
X(multi_strerror) \ | |
X(multi_socket_action) \ | |
X(multi_setopt) \ | |
X(share_init) \ | |
X(share_cleanup) \ | |
X(slist_append) \ | |
X(slist_free_all) | |
#define X(name) static decltype(&curl_ ## name) name = nullptr; | |
CURL_FUNCTIONS | |
#undef X | |
static void* handle = nullptr; | |
static void* load(const char* name) { | |
fprintf(stderr, "loading %s\n", name); | |
void* symbol = dlsym(handle, name); | |
const char* error = dlerror(); | |
if (error) { | |
fprintf(stderr, "Cannot load symbol '%s'\n", name); | |
dlclose(handle); | |
handle = nullptr; | |
abort(); | |
} | |
return symbol; | |
} | |
__attribute__((constructor)) | |
static void load() { | |
assert(!handle); | |
handle = dlopen("libcurl.so.4", RTLD_LAZY | RTLD_LOCAL); | |
if (!handle) { | |
fprintf(stderr, "Could not open shared library '%s'\n", "libcurl.so.4"); | |
abort(); | |
} | |
dlerror(); | |
#define X(name) name = (decltype(&curl_ ## name))load("curl_" #name); | |
CURL_FUNCTIONS | |
#undef X | |
} | |
__attribute__((constructor)) | |
static void unload() { | |
if (handle) { | |
dlclose(handle); | |
} | |
} | |
} // namespace curl |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment