Skip to content

Commit

Permalink
Merge pull request #30 from bartbes/selectable_library_loaders
Browse files Browse the repository at this point in the history
Selectable library loaders, including link-time
  • Loading branch information
MikuAuahDark authored Apr 20, 2024
2 parents 221bb84 + 2fb36d9 commit c40585b
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 80 deletions.
33 changes: 33 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -43,6 +44,18 @@ add_library (https-common STATIC
common/PlaintextConnection.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-linktime-libraryloader STATIC EXCLUDE_FROM_ALL
generic/LinktimeLibraryLoader.cpp
)

add_library (https-curl STATIC EXCLUDE_FROM_ALL
generic/CurlClient.cpp
)
Expand All @@ -68,6 +81,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)
Expand All @@ -92,6 +107,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")
Expand Down Expand Up @@ -124,6 +141,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;linktime")

set_target_properties(https PROPERTIES PREFIX "")

Expand All @@ -134,6 +153,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)
Expand Down Expand Up @@ -175,6 +195,19 @@ 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)
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 ()

### Generate config-generated.h
add_compile_definitions(HTTPS_HAVE_CONFIG_GENERATED_H)
configure_file (
Expand Down
7 changes: 4 additions & 3 deletions src/android/AndroidClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <sstream>
#include <type_traits>

#include <dlfcn.h>
#include "../common/LibraryLoader.h"

// We want std::string that contains null byte, hence length of 1.
// NOLINTNEXTLINE
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/common/HTTPS.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "HTTPS.h"
#include "config.h"
#include "ConnectionClient.h"
#include "LibraryLoader.h"

#include <stdexcept>

Expand Down Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions src/common/LibraryLoader.h
Original file line number Diff line number Diff line change
@@ -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<class T>
inline bool LoadSymbol(T& var, handle *handle, const char *name)
{
var = reinterpret_cast<T>(GetFunction(handle, name));
return var != nullptr;
}
}
3 changes: 3 additions & 0 deletions src/common/config-generated.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
#cmakedefine HTTPS_BACKEND_WININET
#cmakedefine HTTPS_USE_WINSOCK
#cmakedefine DEBUG_SCHANNEL
#cmakedefine HTTPS_LIBRARY_LOADER_WINDOWS
#cmakedefine HTTPS_LIBRARY_LOADER_UNIX
#cmakedefine HTTPS_LIBRARY_LOADER_LINKTIME
5 changes: 5 additions & 0 deletions src/common/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#elif defined(WIN32) || defined(_WIN32)
#define HTTPS_BACKEND_SCHANNEL
#define HTTPS_USE_WINSOCK
#define HTTPS_LIBRARY_LOADER_WINDOWS
#include <winapifamily.h>
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
// WinINet is only supported on desktop.
Expand All @@ -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(<curl/curl.h>)
#define HTTPS_BACKEND_CURL
Expand Down
53 changes: 14 additions & 39 deletions src/generic/CurlClient.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
#ifdef _WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#endif

#include "CurlClient.h"

#ifdef HTTPS_BACKEND_CURL
Expand All @@ -12,30 +7,12 @@
#include <sstream>
#include <vector>

// Dynamic library loader
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

typedef struct StringReader
{
const std::string *str;
size_t pos;
} StringReader;

template <class T>
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)
Expand All @@ -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);
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/generic/CurlClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <curl/curl.h>

#include "../common/HTTPSClient.h"
#include "../common/LibraryLoader.h"

class CurlClient : public HTTPSClient
{
Expand All @@ -19,7 +20,7 @@ class CurlClient : public HTTPSClient
{
Curl();
~Curl();
void *handle;
LibraryLoader::handle *handle;
bool loaded;

decltype(&curl_global_cleanup) global_cleanup;
Expand Down
66 changes: 66 additions & 0 deletions src/generic/LinktimeLibraryLoader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "../common/config.h"
#include "../common/LibraryLoader.h"

#ifdef HTTPS_LIBRARY_LOADER_LINKTIME

#include <cstring>

#ifdef HTTPS_BACKEND_CURL
#include <curl/curl.h>

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<handle *>(&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<function *>(&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

Loading

0 comments on commit c40585b

Please sign in to comment.