From 0668b0fd66dfb934e94aaf0014ba95624f005a79 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 7 Apr 2024 11:53:02 +0200 Subject: [PATCH 1/5] Extract library loading code into its own file Makes it easier to replace, centralises the platform-dependent logic, and means we can more easily re-use things like the templated LoadSymbol. --- src/CMakeLists.txt | 1 + src/android/AndroidClient.cpp | 7 ++-- src/common/HTTPS.cpp | 4 ++ src/common/LibraryLoader.cpp | 54 ++++++++++++++++++++++++ src/common/LibraryLoader.h | 20 +++++++++ src/generic/CurlClient.cpp | 53 +++++++----------------- src/generic/CurlClient.h | 3 +- src/generic/OpenSSLConnection.cpp | 69 ++++++++++++++----------------- 8 files changed, 131 insertions(+), 80 deletions(-) create mode 100644 src/common/LibraryLoader.cpp create mode 100644 src/common/LibraryLoader.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23a8919..e4f7f10 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,7 @@ add_library (https-common STATIC common/HTTPRequest.cpp common/HTTPSClient.cpp common/PlaintextConnection.cpp + common/LibraryLoader.cpp ) add_library (https-curl STATIC EXCLUDE_FROM_ALL diff --git a/src/android/AndroidClient.cpp b/src/android/AndroidClient.cpp index a5994e2..2f11ecb 100644 --- a/src/android/AndroidClient.cpp +++ b/src/android/AndroidClient.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include "../common/LibraryLoader.h" // We want std::string that contains null byte, hence length of 1. // NOLINTNEXTLINE @@ -52,10 +52,11 @@ static std::string getStringUTF(JNIEnv *env, jstring str) AndroidClient::AndroidClient() : HTTPSClient() { + LibraryLoader::handle *library = LibraryLoader::GetCurrentProcessHandle(); // Look for SDL_AndroidGetJNIEnv - SDL_AndroidGetJNIEnv = (decltype(SDL_AndroidGetJNIEnv)) dlsym(RTLD_DEFAULT, "SDL_AndroidGetJNIEnv"); + LibraryLoader::LoadSymbol(SDL_AndroidGetJNIEnv, library, "SDL_AndroidGetJNIEnv"); // Look for SDL_AndroidGetActivity - SDL_AndroidGetActivity = (decltype(SDL_AndroidGetActivity)) dlsym(RTLD_DEFAULT, "SDL_AndroidGetActivity"); + LibraryLoader::LoadSymbol(SDL_AndroidGetActivity, library, "SDL_AndroidGetActivity"); } bool AndroidClient::valid() const diff --git a/src/common/HTTPS.cpp b/src/common/HTTPS.cpp index 2667f2a..7569784 100644 --- a/src/common/HTTPS.cpp +++ b/src/common/HTTPS.cpp @@ -1,6 +1,7 @@ #include "HTTPS.h" #include "config.h" #include "ConnectionClient.h" +#include "LibraryLoader.h" #include @@ -65,6 +66,9 @@ static HTTPSClient *clients[] = { nullptr, }; +// Call into the library loader to make sure it is linked in +static LibraryLoader::handle* dummyProcessHandle = LibraryLoader::GetCurrentProcessHandle(); + HTTPSClient::Reply request(const HTTPSClient::Request &req) { for (size_t i = 0; clients[i]; ++i) diff --git a/src/common/LibraryLoader.cpp b/src/common/LibraryLoader.cpp new file mode 100644 index 0000000..9b31ea3 --- /dev/null +++ b/src/common/LibraryLoader.cpp @@ -0,0 +1,54 @@ +#include "config.h" +#include "LibraryLoader.h" + +#ifdef _WIN32 +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN + +#include +#else +#include +#endif + +namespace LibraryLoader +{ + handle *OpenLibrary(const char *name) + { +#ifdef _WIN32 + return reinterpret_cast(LoadLibraryA(name)); +#else + return dlopen(name, RTLD_LAZY); +#endif + } + + void CloseLibrary(handle *handle) + { + if (handle) + { +#ifdef _WIN32 + FreeLibrary(handle); +#else + dlclose(handle); +#endif + } + } + + handle* GetCurrentProcessHandle() + { +#ifdef _WIN32 + return reinterpret_cast(GetModuleHandle(nullptr)); +#else + return RTLD_DEFAULT; +#endif + } + + function *GetFunction(handle *handle, const char *name) + { +#ifdef _WIN32 + HMODULE nativeHandle = reinterpret_cast(handle); + return reinterpret_cast(GetProcAddress(nativeHandle, name)); +#else + return reinterpret_cast(dlsym(handle, name)); +#endif + } +} diff --git a/src/common/LibraryLoader.h b/src/common/LibraryLoader.h new file mode 100644 index 0000000..49ead46 --- /dev/null +++ b/src/common/LibraryLoader.h @@ -0,0 +1,20 @@ +#pragma once + +namespace LibraryLoader +{ + using handle = void; + using function = void(); + + handle *OpenLibrary(const char *name); + void CloseLibrary(handle *handle); + handle* GetCurrentProcessHandle(); + + function *GetFunction(handle *handle, const char *name); + + template + inline bool LoadSymbol(T& var, handle *handle, const char *name) + { + var = reinterpret_cast(GetFunction(handle, name)); + return var != nullptr; + } +} diff --git a/src/generic/CurlClient.cpp b/src/generic/CurlClient.cpp index ac84689..8ae728c 100644 --- a/src/generic/CurlClient.cpp +++ b/src/generic/CurlClient.cpp @@ -1,8 +1,3 @@ -#ifdef _WIN32 -#define NOMINMAX -#define WIN32_LEAN_AND_MEAN -#endif - #include "CurlClient.h" #ifdef HTTPS_BACKEND_CURL @@ -12,30 +7,12 @@ #include #include -// Dynamic library loader -#ifdef _WIN32 -#include -#else -#include -#endif - typedef struct StringReader { const std::string *str; size_t pos; } StringReader; -template -static inline bool loadSymbol(T &var, void *handle, const char *name) -{ -#ifdef _WIN32 - var = (T) GetProcAddress((HMODULE) handle, name); -#else - var = (T) dlsym(handle, name); -#endif - return var != nullptr; -} - CurlClient::Curl::Curl() : handle(nullptr) , loaded(false) @@ -48,33 +25,35 @@ CurlClient::Curl::Curl() , slist_append(nullptr) , slist_free_all(nullptr) { + using namespace LibraryLoader; + #ifdef _WIN32 - handle = (void *) LoadLibraryA("libcurl.dll"); + handle = OpenLibrary("libcurl.dll"); #else - handle = dlopen("libcurl.so.4", RTLD_LAZY); + handle = OpenLibrary("libcurl.so.4"); #endif if (!handle) return; // Load symbols decltype(&curl_global_init) global_init = nullptr; - if (!loadSymbol(global_init, handle, "curl_global_init")) + if (!LoadSymbol(global_init, handle, "curl_global_init")) return; - if (!loadSymbol(global_cleanup, handle, "curl_global_cleanup")) + if (!LoadSymbol(global_cleanup, handle, "curl_global_cleanup")) return; - if (!loadSymbol(easy_init, handle, "curl_easy_init")) + if (!LoadSymbol(easy_init, handle, "curl_easy_init")) return; - if (!loadSymbol(easy_cleanup, handle, "curl_easy_cleanup")) + if (!LoadSymbol(easy_cleanup, handle, "curl_easy_cleanup")) return; - if (!loadSymbol(easy_setopt, handle, "curl_easy_setopt")) + if (!LoadSymbol(easy_setopt, handle, "curl_easy_setopt")) return; - if (!loadSymbol(easy_perform, handle, "curl_easy_perform")) + if (!LoadSymbol(easy_perform, handle, "curl_easy_perform")) return; - if (!loadSymbol(easy_getinfo, handle, "curl_easy_getinfo")) + if (!LoadSymbol(easy_getinfo, handle, "curl_easy_getinfo")) return; - if (!loadSymbol(slist_append, handle, "curl_slist_append")) + if (!LoadSymbol(slist_append, handle, "curl_slist_append")) return; - if (!loadSymbol(slist_free_all, handle, "curl_slist_free_all")) + if (!LoadSymbol(slist_free_all, handle, "curl_slist_free_all")) return; global_init(CURL_GLOBAL_DEFAULT); @@ -87,11 +66,7 @@ CurlClient::Curl::~Curl() global_cleanup(); if (handle) -#ifdef _WIN32 - FreeLibrary((HMODULE) handle); -#else - dlclose(handle); -#endif + LibraryLoader::CloseLibrary(handle); } static char toUppercase(char c) diff --git a/src/generic/CurlClient.h b/src/generic/CurlClient.h index 30d4a9b..3761f36 100644 --- a/src/generic/CurlClient.h +++ b/src/generic/CurlClient.h @@ -7,6 +7,7 @@ #include #include "../common/HTTPSClient.h" +#include "../common/LibraryLoader.h" class CurlClient : public HTTPSClient { @@ -19,7 +20,7 @@ class CurlClient : public HTTPSClient { Curl(); ~Curl(); - void *handle; + LibraryLoader::handle *handle; bool loaded; decltype(&curl_global_cleanup) global_cleanup; diff --git a/src/generic/OpenSSLConnection.cpp b/src/generic/OpenSSLConnection.cpp index e1f2dd7..658f24f 100644 --- a/src/generic/OpenSSLConnection.cpp +++ b/src/generic/OpenSSLConnection.cpp @@ -2,65 +2,60 @@ #ifdef HTTPS_BACKEND_OPENSSL -#include +#include "../common/LibraryLoader.h" // Not present in openssl 1.1 headers #define SSL_CTRL_OPTIONS 32 -template -static inline bool loadSymbol(T &var, void *handle, const char *name) -{ - var = reinterpret_cast(dlsym(handle, name)); - return var != nullptr; -} - OpenSSLConnection::SSLFuncs::SSLFuncs() { + using namespace LibraryLoader; + valid = false; // Try OpenSSL 1.1 - void *sslhandle = dlopen("libssl.so.1.1", RTLD_LAZY); - void *cryptohandle = dlopen("libcrypto.so.1.1", RTLD_LAZY); + handle *sslhandle = OpenLibrary("libssl.so.1.1"); + handle *cryptohandle = OpenLibrary("libcrypto.so.1.1"); // Try OpenSSL 1.0 if (!sslhandle || !cryptohandle) { - sslhandle = dlopen("libssl.so.1.0.0", RTLD_LAZY); - cryptohandle = dlopen("libcrypto.so.1.0.0", RTLD_LAZY); + sslhandle = OpenLibrary("libssl.so.1.0.0"); + cryptohandle = OpenLibrary("libcrypto.so.1.0.0"); } // Try OpenSSL without version if (!sslhandle || !cryptohandle) { - sslhandle = dlopen("libssl.so", RTLD_LAZY); - cryptohandle = dlopen("libcrypto.so", RTLD_LAZY); + sslhandle = OpenLibrary("libssl.so"); + cryptohandle = OpenLibrary("libcrypto.so"); } // Give up if (!sslhandle || !cryptohandle) return; valid = true; - valid = valid && (loadSymbol(library_init, sslhandle, "SSL_library_init") || - loadSymbol(init_ssl, sslhandle, "OPENSSL_init_ssl")); - - valid = valid && loadSymbol(CTX_new, sslhandle, "SSL_CTX_new"); - valid = valid && loadSymbol(CTX_ctrl, sslhandle, "SSL_CTX_ctrl"); - valid = valid && loadSymbol(CTX_set_verify, sslhandle, "SSL_CTX_set_verify"); - valid = valid && loadSymbol(CTX_set_default_verify_paths, sslhandle, "SSL_CTX_set_default_verify_paths"); - valid = valid && loadSymbol(CTX_free, sslhandle, "SSL_CTX_free"); - - valid = valid && loadSymbol(SSL_new, sslhandle, "SSL_new"); - valid = valid && loadSymbol(SSL_free, sslhandle, "SSL_free"); - valid = valid && loadSymbol(set_fd, sslhandle, "SSL_set_fd"); - valid = valid && loadSymbol(connect, sslhandle, "SSL_connect"); - valid = valid && loadSymbol(read, sslhandle, "SSL_read"); - valid = valid && loadSymbol(write, sslhandle, "SSL_write"); - valid = valid && loadSymbol(shutdown, sslhandle, "SSL_shutdown"); - valid = valid && loadSymbol(get_verify_result, sslhandle, "SSL_get_verify_result"); - valid = valid && loadSymbol(get_peer_certificate, sslhandle, "SSL_get_peer_certificate"); - - valid = valid && (loadSymbol(SSLv23_method, sslhandle, "SSLv23_method") || - loadSymbol(SSLv23_method, sslhandle, "TLS_method")); - - valid = valid && loadSymbol(check_host, cryptohandle, "X509_check_host"); + valid = valid && (LoadSymbol(library_init, sslhandle, "SSL_library_init") || + LoadSymbol(init_ssl, sslhandle, "OPENSSL_init_ssl")); + + valid = valid && LoadSymbol(CTX_new, sslhandle, "SSL_CTX_new"); + valid = valid && LoadSymbol(CTX_ctrl, sslhandle, "SSL_CTX_ctrl"); + valid = valid && LoadSymbol(CTX_set_verify, sslhandle, "SSL_CTX_set_verify"); + valid = valid && LoadSymbol(CTX_set_default_verify_paths, sslhandle, "SSL_CTX_set_default_verify_paths"); + valid = valid && LoadSymbol(CTX_free, sslhandle, "SSL_CTX_free"); + + valid = valid && LoadSymbol(SSL_new, sslhandle, "SSL_new"); + valid = valid && LoadSymbol(SSL_free, sslhandle, "SSL_free"); + valid = valid && LoadSymbol(set_fd, sslhandle, "SSL_set_fd"); + valid = valid && LoadSymbol(connect, sslhandle, "SSL_connect"); + valid = valid && LoadSymbol(read, sslhandle, "SSL_read"); + valid = valid && LoadSymbol(write, sslhandle, "SSL_write"); + valid = valid && LoadSymbol(shutdown, sslhandle, "SSL_shutdown"); + valid = valid && LoadSymbol(get_verify_result, sslhandle, "SSL_get_verify_result"); + valid = valid && LoadSymbol(get_peer_certificate, sslhandle, "SSL_get_peer_certificate"); + + valid = valid && (LoadSymbol(SSLv23_method, sslhandle, "SSLv23_method") || + LoadSymbol(SSLv23_method, sslhandle, "TLS_method")); + + valid = valid && LoadSymbol(check_host, cryptohandle, "X509_check_host"); if (library_init) library_init(); From ded519c7eff78d27ab5b12e7c5e2a440bf3ca8df Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 7 Apr 2024 11:59:26 +0200 Subject: [PATCH 2/5] Make library loader selectable --- src/CMakeLists.txt | 25 +++++++++++++- src/common/config-generated.h.in | 2 ++ src/common/config.h | 5 +++ src/generic/UnixLibraryLoader.cpp | 33 +++++++++++++++++++ .../WindowsLibraryLoader.cpp} | 29 +++------------- 5 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 src/generic/UnixLibraryLoader.cpp rename src/{common/LibraryLoader.cpp => windows/WindowsLibraryLoader.cpp} (62%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4f7f10..ab3a00a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,14 @@ add_library (https-common STATIC common/HTTPRequest.cpp common/HTTPSClient.cpp common/PlaintextConnection.cpp - common/LibraryLoader.cpp +) + +add_library (https-windows-libraryloader STATIC EXCLUDE_FROM_ALL + windows/WindowsLibraryLoader.cpp +) + +add_library (https-unix-libraryloader STATIC EXCLUDE_FROM_ALL + generic/UnixLibraryLoader.cpp ) add_library (https-curl STATIC EXCLUDE_FROM_ALL @@ -69,6 +76,8 @@ add_library (https-wininet STATIC EXCLUDE_FROM_ALL ) ### Flags +set (LIBRARY_LOADER_DEFAULT "unix") + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") option (USE_CURL_BACKEND "Use the libcurl backend" ON) option (USE_OPENSSL_BACKEND "Use the openssl backend" ON) @@ -93,6 +102,8 @@ elseif (WIN32) option (USE_WINSOCK "Use winsock instead of BSD sockets (windows-only)" ON) + set (LIBRARY_LOADER_DEFAULT "windows") + # Windows needs to link with Lua libraries target_link_libraries(https ${LUA_LIBRARIES}) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") @@ -125,6 +136,8 @@ elseif (ANDROID) target_link_libraries(https ${LUA_LIBRARIES}) endif () option (DEBUG_SCHANNEL "Enable debug output in schannel backend" OFF) +set (LIBRARY_LOADER ${LIBRARY_LOADER_DEFAULT} CACHE STRING "Which method to use to dynamically load libraries") +set_property (CACHE LIBRARY_LOADER PROPERTY STRINGS "unix;windows") set_target_properties(https PROPERTIES PREFIX "") @@ -176,6 +189,16 @@ if (USE_WINSOCK) set(HTTPS_USE_WINSOCK ON) endif () +if ("${LIBRARY_LOADER}" STREQUAL "unix") + set(HTTPS_LIBRARY_LOADER_UNIX ON) + target_link_libraries (https https-unix-libraryloader) +elseif ("${LIBRARY_LOADER}" STREQUAL "windows") + set(HTTPS_LIBRARY_LOADER_WINDOWS ON) + target_link_libraries (https https-windows-libraryloader) +else () + message(WARNING "No library loader selected, backends that depend on dynamic loading will be broken") +endif () + ### Generate config-generated.h add_compile_definitions(HTTPS_HAVE_CONFIG_GENERATED_H) configure_file ( diff --git a/src/common/config-generated.h.in b/src/common/config-generated.h.in index 08403cb..c5a8b59 100644 --- a/src/common/config-generated.h.in +++ b/src/common/config-generated.h.in @@ -6,3 +6,5 @@ #cmakedefine HTTPS_BACKEND_WININET #cmakedefine HTTPS_USE_WINSOCK #cmakedefine DEBUG_SCHANNEL +#cmakedefine HTTPS_LIBRARY_LOADER_WINDOWS +#cmakedefine HTTPS_LIBRARY_LOADER_UNIX diff --git a/src/common/config.h b/src/common/config.h index 4068e9b..97b8200 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -10,6 +10,7 @@ #elif defined(WIN32) || defined(_WIN32) #define HTTPS_BACKEND_SCHANNEL #define HTTPS_USE_WINSOCK + #define HTTPS_LIBRARY_LOADER_WINDOWS #include #if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) // WinINet is only supported on desktop. @@ -23,9 +24,13 @@ #endif #elif defined(__ANDROID__) #define HTTPS_BACKEND_ANDROID + #define HTTPS_LIBRARY_LOADER_UNIX #elif defined(__APPLE__) #define HTTPS_BACKEND_NSURL + #define HTTPS_LIBRARY_LOADER_UNIX #elif defined(linux) || defined(__linux) || defined(__linux__) + #define HTTPS_LIBRARY_LOADER_UNIX + #if defined __has_include #if __has_include() #define HTTPS_BACKEND_CURL diff --git a/src/generic/UnixLibraryLoader.cpp b/src/generic/UnixLibraryLoader.cpp new file mode 100644 index 0000000..55dc728 --- /dev/null +++ b/src/generic/UnixLibraryLoader.cpp @@ -0,0 +1,33 @@ +#include "../common/config.h" +#include "../common/LibraryLoader.h" + +#ifdef HTTPS_LIBRARY_LOADER_UNIX + +#include + +namespace LibraryLoader +{ + handle *OpenLibrary(const char *name) + { + return dlopen(name, RTLD_LAZY); + } + + void CloseLibrary(handle *handle) + { + if (handle) + dlclose(handle); + } + + handle* GetCurrentProcessHandle() + { + return RTLD_DEFAULT; + } + + function *GetFunction(handle *handle, const char *name) + { + return reinterpret_cast(dlsym(handle, name)); + } +} + +#endif // HTTPS_LIBRARY_LOADER_UNIX + diff --git a/src/common/LibraryLoader.cpp b/src/windows/WindowsLibraryLoader.cpp similarity index 62% rename from src/common/LibraryLoader.cpp rename to src/windows/WindowsLibraryLoader.cpp index 9b31ea3..62f865a 100644 --- a/src/common/LibraryLoader.cpp +++ b/src/windows/WindowsLibraryLoader.cpp @@ -1,54 +1,35 @@ -#include "config.h" -#include "LibraryLoader.h" +#include "../common/config.h" +#include "../common/LibraryLoader.h" -#ifdef _WIN32 +#ifdef HTTPS_LIBRARY_LOADER_WINDOWS #define NOMINMAX #define WIN32_LEAN_AND_MEAN #include -#else -#include -#endif namespace LibraryLoader { handle *OpenLibrary(const char *name) { -#ifdef _WIN32 return reinterpret_cast(LoadLibraryA(name)); -#else - return dlopen(name, RTLD_LAZY); -#endif } void CloseLibrary(handle *handle) { if (handle) - { -#ifdef _WIN32 FreeLibrary(handle); -#else - dlclose(handle); -#endif - } } handle* GetCurrentProcessHandle() { -#ifdef _WIN32 return reinterpret_cast(GetModuleHandle(nullptr)); -#else - return RTLD_DEFAULT; -#endif } function *GetFunction(handle *handle, const char *name) { -#ifdef _WIN32 HMODULE nativeHandle = reinterpret_cast(handle); return reinterpret_cast(GetProcAddress(nativeHandle, name)); -#else - return reinterpret_cast(dlsym(handle, name)); -#endif } } + +#endif // HTTPS_LIBRARY_LOADER_WINDOWS From 56a1ed18c98714104aea9408094ea9fb74f8c09a Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 7 Apr 2024 12:23:16 +0200 Subject: [PATCH 3/5] Add link-time library loader Which does not call dlsym or equivalents, but links directly against the library and dispatches on name. This can be useful on platforms without (working) dlsym-implementations, without affecting the structure of lua-https too much. --- src/CMakeLists.txt | 10 +++- src/common/config-generated.h.in | 1 + src/generic/LinktimeLibraryLoader.cpp | 66 +++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/generic/LinktimeLibraryLoader.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab3a00a..304fe0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,10 @@ add_library (https-unix-libraryloader STATIC EXCLUDE_FROM_ALL generic/UnixLibraryLoader.cpp ) +add_library (https-linktime-libraryloader STATIC EXCLUDE_FROM_ALL + generic/LinktimeLibraryLoader.cpp +) + add_library (https-curl STATIC EXCLUDE_FROM_ALL generic/CurlClient.cpp ) @@ -137,7 +141,7 @@ elseif (ANDROID) endif () option (DEBUG_SCHANNEL "Enable debug output in schannel backend" OFF) set (LIBRARY_LOADER ${LIBRARY_LOADER_DEFAULT} CACHE STRING "Which method to use to dynamically load libraries") -set_property (CACHE LIBRARY_LOADER PROPERTY STRINGS "unix;windows") +set_property (CACHE LIBRARY_LOADER PROPERTY STRINGS "unix;windows;linktime") set_target_properties(https PROPERTIES PREFIX "") @@ -148,6 +152,7 @@ if (USE_CURL_BACKEND) find_package (CURL REQUIRED) include_directories (${CURL_INCLUDE_DIRS}) target_link_libraries (https https-curl) + target_link_libraries (https-linktime-libraryloader ${CURL_LIBRARY}) endif () if (USE_OPENSSL_BACKEND) @@ -195,6 +200,9 @@ if ("${LIBRARY_LOADER}" STREQUAL "unix") elseif ("${LIBRARY_LOADER}" STREQUAL "windows") set(HTTPS_LIBRARY_LOADER_WINDOWS ON) target_link_libraries (https https-windows-libraryloader) +elseif ("${LIBRARY_LOADER}" STREQUAL "linktime") + set(HTTPS_LIBRARY_LOADER_LINKTIME ON) + target_link_libraries (https https-linktime-libraryloader) else () message(WARNING "No library loader selected, backends that depend on dynamic loading will be broken") endif () diff --git a/src/common/config-generated.h.in b/src/common/config-generated.h.in index c5a8b59..625cd2a 100644 --- a/src/common/config-generated.h.in +++ b/src/common/config-generated.h.in @@ -8,3 +8,4 @@ #cmakedefine DEBUG_SCHANNEL #cmakedefine HTTPS_LIBRARY_LOADER_WINDOWS #cmakedefine HTTPS_LIBRARY_LOADER_UNIX +#cmakedefine HTTPS_LIBRARY_LOADER_LINKTIME diff --git a/src/generic/LinktimeLibraryLoader.cpp b/src/generic/LinktimeLibraryLoader.cpp new file mode 100644 index 0000000..ffca21d --- /dev/null +++ b/src/generic/LinktimeLibraryLoader.cpp @@ -0,0 +1,66 @@ +#include "../common/config.h" +#include "../common/LibraryLoader.h" + +#ifdef HTTPS_LIBRARY_LOADER_LINKTIME + +#include + +#ifdef HTTPS_BACKEND_CURL +#include + +static char CurlHandle; +#endif + +#if defined(HTTPS_BACKEND_OPENSSL) || defined(HTTPS_BACKEND_ANDROID) +# error "Selected backends that are not compatible with this loader" +#endif + +namespace LibraryLoader +{ + handle *OpenLibrary(const char *name) + { +#ifdef HTTPS_BACKEND_CURL + if (strstr(name, "libcurl") == name) + return reinterpret_cast(&CurlHandle); +#endif + return nullptr; + } + + void CloseLibrary(handle *) + { + } + + handle* GetCurrentProcessHandle() + { + return nullptr; + } + + function *GetFunction(handle *handle, const char *name) + { +#define RETURN_MATCHING_FUNCTION(func) \ + if (strcmp(name, #func) == 0) \ + return reinterpret_cast(&func); + +#ifdef HTTPS_BACKEND_CURL + if (handle == &CurlHandle) + { + RETURN_MATCHING_FUNCTION(curl_global_init); + RETURN_MATCHING_FUNCTION(curl_global_cleanup); + RETURN_MATCHING_FUNCTION(curl_easy_init); + RETURN_MATCHING_FUNCTION(curl_easy_cleanup); + RETURN_MATCHING_FUNCTION(curl_easy_setopt); + RETURN_MATCHING_FUNCTION(curl_easy_perform); + RETURN_MATCHING_FUNCTION(curl_easy_getinfo); + RETURN_MATCHING_FUNCTION(curl_slist_append); + RETURN_MATCHING_FUNCTION(curl_slist_free_all); + } +#endif + +#undef RETURN_MATCHING_FUNCTION + + return nullptr; + } +} + +#endif // HTTPS_LIBRARY_LOADER_LINKTIME + From 938d49a56bc16eab2a78002c2c03e242b46b1e34 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 7 Apr 2024 13:16:19 +0200 Subject: [PATCH 4/5] Fix missing cast in WindowsLibraryLoader --- src/windows/WindowsLibraryLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/WindowsLibraryLoader.cpp b/src/windows/WindowsLibraryLoader.cpp index 62f865a..d365aea 100644 --- a/src/windows/WindowsLibraryLoader.cpp +++ b/src/windows/WindowsLibraryLoader.cpp @@ -17,7 +17,7 @@ namespace LibraryLoader void CloseLibrary(handle *handle) { if (handle) - FreeLibrary(handle); + FreeLibrary(reinterpret_cast(handle)); } handle* GetCurrentProcessHandle() From 2fb36d99448e7c1ef9e021b23d8b4542eeac6c46 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Sun, 7 Apr 2024 13:19:38 +0200 Subject: [PATCH 5/5] Make sure at least C++11 is used Apparently on macOS we weren't building using c++11, causing a compile error because of a nullptr. Considering the ubiquitous support for c++11 these days, just enable it. --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 304fe0a..0e3ceff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 3.13) ### Basic compilation settings set (CMAKE_POSITION_INDEPENDENT_CODE TRUE) +set (CMAKE_CXX_STANDARD 11) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}