Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selectable library loaders, including link-time #30

Merged
merged 5 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading