Skip to content

Commit c40585b

Browse files
authored
Merge pull request #30 from bartbes/selectable_library_loaders
Selectable library loaders, including link-time
2 parents 221bb84 + 2fb36d9 commit c40585b

12 files changed

+251
-80
lines changed

src/CMakeLists.txt

+33
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 3.13)
22

33
### Basic compilation settings
44
set (CMAKE_POSITION_INDEPENDENT_CODE TRUE)
5+
set (CMAKE_CXX_STANDARD 11)
56

67
include_directories (
78
${CMAKE_CURRENT_SOURCE_DIR}
@@ -43,6 +44,18 @@ add_library (https-common STATIC
4344
common/PlaintextConnection.cpp
4445
)
4546

47+
add_library (https-windows-libraryloader STATIC EXCLUDE_FROM_ALL
48+
windows/WindowsLibraryLoader.cpp
49+
)
50+
51+
add_library (https-unix-libraryloader STATIC EXCLUDE_FROM_ALL
52+
generic/UnixLibraryLoader.cpp
53+
)
54+
55+
add_library (https-linktime-libraryloader STATIC EXCLUDE_FROM_ALL
56+
generic/LinktimeLibraryLoader.cpp
57+
)
58+
4659
add_library (https-curl STATIC EXCLUDE_FROM_ALL
4760
generic/CurlClient.cpp
4861
)
@@ -68,6 +81,8 @@ add_library (https-wininet STATIC EXCLUDE_FROM_ALL
6881
)
6982

7083
### Flags
84+
set (LIBRARY_LOADER_DEFAULT "unix")
85+
7186
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
7287
option (USE_CURL_BACKEND "Use the libcurl backend" ON)
7388
option (USE_OPENSSL_BACKEND "Use the openssl backend" ON)
@@ -92,6 +107,8 @@ elseif (WIN32)
92107

93108
option (USE_WINSOCK "Use winsock instead of BSD sockets (windows-only)" ON)
94109

110+
set (LIBRARY_LOADER_DEFAULT "windows")
111+
95112
# Windows needs to link with Lua libraries
96113
target_link_libraries(https ${LUA_LIBRARIES})
97114
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
@@ -124,6 +141,8 @@ elseif (ANDROID)
124141
target_link_libraries(https ${LUA_LIBRARIES})
125142
endif ()
126143
option (DEBUG_SCHANNEL "Enable debug output in schannel backend" OFF)
144+
set (LIBRARY_LOADER ${LIBRARY_LOADER_DEFAULT} CACHE STRING "Which method to use to dynamically load libraries")
145+
set_property (CACHE LIBRARY_LOADER PROPERTY STRINGS "unix;windows;linktime")
127146

128147
set_target_properties(https PROPERTIES PREFIX "")
129148

@@ -134,6 +153,7 @@ if (USE_CURL_BACKEND)
134153
find_package (CURL REQUIRED)
135154
include_directories (${CURL_INCLUDE_DIRS})
136155
target_link_libraries (https https-curl)
156+
target_link_libraries (https-linktime-libraryloader ${CURL_LIBRARY})
137157
endif ()
138158

139159
if (USE_OPENSSL_BACKEND)
@@ -175,6 +195,19 @@ if (USE_WINSOCK)
175195
set(HTTPS_USE_WINSOCK ON)
176196
endif ()
177197

198+
if ("${LIBRARY_LOADER}" STREQUAL "unix")
199+
set(HTTPS_LIBRARY_LOADER_UNIX ON)
200+
target_link_libraries (https https-unix-libraryloader)
201+
elseif ("${LIBRARY_LOADER}" STREQUAL "windows")
202+
set(HTTPS_LIBRARY_LOADER_WINDOWS ON)
203+
target_link_libraries (https https-windows-libraryloader)
204+
elseif ("${LIBRARY_LOADER}" STREQUAL "linktime")
205+
set(HTTPS_LIBRARY_LOADER_LINKTIME ON)
206+
target_link_libraries (https https-linktime-libraryloader)
207+
else ()
208+
message(WARNING "No library loader selected, backends that depend on dynamic loading will be broken")
209+
endif ()
210+
178211
### Generate config-generated.h
179212
add_compile_definitions(HTTPS_HAVE_CONFIG_GENERATED_H)
180213
configure_file (

src/android/AndroidClient.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <sstream>
66
#include <type_traits>
77

8-
#include <dlfcn.h>
8+
#include "../common/LibraryLoader.h"
99

1010
// We want std::string that contains null byte, hence length of 1.
1111
// NOLINTNEXTLINE
@@ -52,10 +52,11 @@ static std::string getStringUTF(JNIEnv *env, jstring str)
5252
AndroidClient::AndroidClient()
5353
: HTTPSClient()
5454
{
55+
LibraryLoader::handle *library = LibraryLoader::GetCurrentProcessHandle();
5556
// Look for SDL_AndroidGetJNIEnv
56-
SDL_AndroidGetJNIEnv = (decltype(SDL_AndroidGetJNIEnv)) dlsym(RTLD_DEFAULT, "SDL_AndroidGetJNIEnv");
57+
LibraryLoader::LoadSymbol(SDL_AndroidGetJNIEnv, library, "SDL_AndroidGetJNIEnv");
5758
// Look for SDL_AndroidGetActivity
58-
SDL_AndroidGetActivity = (decltype(SDL_AndroidGetActivity)) dlsym(RTLD_DEFAULT, "SDL_AndroidGetActivity");
59+
LibraryLoader::LoadSymbol(SDL_AndroidGetActivity, library, "SDL_AndroidGetActivity");
5960
}
6061

6162
bool AndroidClient::valid() const

src/common/HTTPS.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "HTTPS.h"
22
#include "config.h"
33
#include "ConnectionClient.h"
4+
#include "LibraryLoader.h"
45

56
#include <stdexcept>
67

@@ -65,6 +66,9 @@ static HTTPSClient *clients[] = {
6566
nullptr,
6667
};
6768

69+
// Call into the library loader to make sure it is linked in
70+
static LibraryLoader::handle* dummyProcessHandle = LibraryLoader::GetCurrentProcessHandle();
71+
6872
HTTPSClient::Reply request(const HTTPSClient::Request &req)
6973
{
7074
for (size_t i = 0; clients[i]; ++i)

src/common/LibraryLoader.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
3+
namespace LibraryLoader
4+
{
5+
using handle = void;
6+
using function = void();
7+
8+
handle *OpenLibrary(const char *name);
9+
void CloseLibrary(handle *handle);
10+
handle* GetCurrentProcessHandle();
11+
12+
function *GetFunction(handle *handle, const char *name);
13+
14+
template<class T>
15+
inline bool LoadSymbol(T& var, handle *handle, const char *name)
16+
{
17+
var = reinterpret_cast<T>(GetFunction(handle, name));
18+
return var != nullptr;
19+
}
20+
}

src/common/config-generated.h.in

+3
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
#cmakedefine HTTPS_BACKEND_WININET
77
#cmakedefine HTTPS_USE_WINSOCK
88
#cmakedefine DEBUG_SCHANNEL
9+
#cmakedefine HTTPS_LIBRARY_LOADER_WINDOWS
10+
#cmakedefine HTTPS_LIBRARY_LOADER_UNIX
11+
#cmakedefine HTTPS_LIBRARY_LOADER_LINKTIME

src/common/config.h

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#elif defined(WIN32) || defined(_WIN32)
1111
#define HTTPS_BACKEND_SCHANNEL
1212
#define HTTPS_USE_WINSOCK
13+
#define HTTPS_LIBRARY_LOADER_WINDOWS
1314
#include <winapifamily.h>
1415
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
1516
// WinINet is only supported on desktop.
@@ -23,9 +24,13 @@
2324
#endif
2425
#elif defined(__ANDROID__)
2526
#define HTTPS_BACKEND_ANDROID
27+
#define HTTPS_LIBRARY_LOADER_UNIX
2628
#elif defined(__APPLE__)
2729
#define HTTPS_BACKEND_NSURL
30+
#define HTTPS_LIBRARY_LOADER_UNIX
2831
#elif defined(linux) || defined(__linux) || defined(__linux__)
32+
#define HTTPS_LIBRARY_LOADER_UNIX
33+
2934
#if defined __has_include
3035
#if __has_include(<curl/curl.h>)
3136
#define HTTPS_BACKEND_CURL

src/generic/CurlClient.cpp

+14-39
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
#ifdef _WIN32
2-
#define NOMINMAX
3-
#define WIN32_LEAN_AND_MEAN
4-
#endif
5-
61
#include "CurlClient.h"
72

83
#ifdef HTTPS_BACKEND_CURL
@@ -12,30 +7,12 @@
127
#include <sstream>
138
#include <vector>
149

15-
// Dynamic library loader
16-
#ifdef _WIN32
17-
#include <windows.h>
18-
#else
19-
#include <dlfcn.h>
20-
#endif
21-
2210
typedef struct StringReader
2311
{
2412
const std::string *str;
2513
size_t pos;
2614
} StringReader;
2715

28-
template <class T>
29-
static inline bool loadSymbol(T &var, void *handle, const char *name)
30-
{
31-
#ifdef _WIN32
32-
var = (T) GetProcAddress((HMODULE) handle, name);
33-
#else
34-
var = (T) dlsym(handle, name);
35-
#endif
36-
return var != nullptr;
37-
}
38-
3916
CurlClient::Curl::Curl()
4017
: handle(nullptr)
4118
, loaded(false)
@@ -48,33 +25,35 @@ CurlClient::Curl::Curl()
4825
, slist_append(nullptr)
4926
, slist_free_all(nullptr)
5027
{
28+
using namespace LibraryLoader;
29+
5130
#ifdef _WIN32
52-
handle = (void *) LoadLibraryA("libcurl.dll");
31+
handle = OpenLibrary("libcurl.dll");
5332
#else
54-
handle = dlopen("libcurl.so.4", RTLD_LAZY);
33+
handle = OpenLibrary("libcurl.so.4");
5534
#endif
5635
if (!handle)
5736
return;
5837

5938
// Load symbols
6039
decltype(&curl_global_init) global_init = nullptr;
61-
if (!loadSymbol(global_init, handle, "curl_global_init"))
40+
if (!LoadSymbol(global_init, handle, "curl_global_init"))
6241
return;
63-
if (!loadSymbol(global_cleanup, handle, "curl_global_cleanup"))
42+
if (!LoadSymbol(global_cleanup, handle, "curl_global_cleanup"))
6443
return;
65-
if (!loadSymbol(easy_init, handle, "curl_easy_init"))
44+
if (!LoadSymbol(easy_init, handle, "curl_easy_init"))
6645
return;
67-
if (!loadSymbol(easy_cleanup, handle, "curl_easy_cleanup"))
46+
if (!LoadSymbol(easy_cleanup, handle, "curl_easy_cleanup"))
6847
return;
69-
if (!loadSymbol(easy_setopt, handle, "curl_easy_setopt"))
48+
if (!LoadSymbol(easy_setopt, handle, "curl_easy_setopt"))
7049
return;
71-
if (!loadSymbol(easy_perform, handle, "curl_easy_perform"))
50+
if (!LoadSymbol(easy_perform, handle, "curl_easy_perform"))
7251
return;
73-
if (!loadSymbol(easy_getinfo, handle, "curl_easy_getinfo"))
52+
if (!LoadSymbol(easy_getinfo, handle, "curl_easy_getinfo"))
7453
return;
75-
if (!loadSymbol(slist_append, handle, "curl_slist_append"))
54+
if (!LoadSymbol(slist_append, handle, "curl_slist_append"))
7655
return;
77-
if (!loadSymbol(slist_free_all, handle, "curl_slist_free_all"))
56+
if (!LoadSymbol(slist_free_all, handle, "curl_slist_free_all"))
7857
return;
7958

8059
global_init(CURL_GLOBAL_DEFAULT);
@@ -87,11 +66,7 @@ CurlClient::Curl::~Curl()
8766
global_cleanup();
8867

8968
if (handle)
90-
#ifdef _WIN32
91-
FreeLibrary((HMODULE) handle);
92-
#else
93-
dlclose(handle);
94-
#endif
69+
LibraryLoader::CloseLibrary(handle);
9570
}
9671

9772
static char toUppercase(char c)

src/generic/CurlClient.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <curl/curl.h>
88

99
#include "../common/HTTPSClient.h"
10+
#include "../common/LibraryLoader.h"
1011

1112
class CurlClient : public HTTPSClient
1213
{
@@ -19,7 +20,7 @@ class CurlClient : public HTTPSClient
1920
{
2021
Curl();
2122
~Curl();
22-
void *handle;
23+
LibraryLoader::handle *handle;
2324
bool loaded;
2425

2526
decltype(&curl_global_cleanup) global_cleanup;

src/generic/LinktimeLibraryLoader.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "../common/config.h"
2+
#include "../common/LibraryLoader.h"
3+
4+
#ifdef HTTPS_LIBRARY_LOADER_LINKTIME
5+
6+
#include <cstring>
7+
8+
#ifdef HTTPS_BACKEND_CURL
9+
#include <curl/curl.h>
10+
11+
static char CurlHandle;
12+
#endif
13+
14+
#if defined(HTTPS_BACKEND_OPENSSL) || defined(HTTPS_BACKEND_ANDROID)
15+
# error "Selected backends that are not compatible with this loader"
16+
#endif
17+
18+
namespace LibraryLoader
19+
{
20+
handle *OpenLibrary(const char *name)
21+
{
22+
#ifdef HTTPS_BACKEND_CURL
23+
if (strstr(name, "libcurl") == name)
24+
return reinterpret_cast<handle *>(&CurlHandle);
25+
#endif
26+
return nullptr;
27+
}
28+
29+
void CloseLibrary(handle *)
30+
{
31+
}
32+
33+
handle* GetCurrentProcessHandle()
34+
{
35+
return nullptr;
36+
}
37+
38+
function *GetFunction(handle *handle, const char *name)
39+
{
40+
#define RETURN_MATCHING_FUNCTION(func) \
41+
if (strcmp(name, #func) == 0) \
42+
return reinterpret_cast<function *>(&func);
43+
44+
#ifdef HTTPS_BACKEND_CURL
45+
if (handle == &CurlHandle)
46+
{
47+
RETURN_MATCHING_FUNCTION(curl_global_init);
48+
RETURN_MATCHING_FUNCTION(curl_global_cleanup);
49+
RETURN_MATCHING_FUNCTION(curl_easy_init);
50+
RETURN_MATCHING_FUNCTION(curl_easy_cleanup);
51+
RETURN_MATCHING_FUNCTION(curl_easy_setopt);
52+
RETURN_MATCHING_FUNCTION(curl_easy_perform);
53+
RETURN_MATCHING_FUNCTION(curl_easy_getinfo);
54+
RETURN_MATCHING_FUNCTION(curl_slist_append);
55+
RETURN_MATCHING_FUNCTION(curl_slist_free_all);
56+
}
57+
#endif
58+
59+
#undef RETURN_MATCHING_FUNCTION
60+
61+
return nullptr;
62+
}
63+
}
64+
65+
#endif // HTTPS_LIBRARY_LOADER_LINKTIME
66+

0 commit comments

Comments
 (0)