Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
13 changes: 7 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,16 @@ XLDFLAGS += $(LIBWEBSOCKETS_DIR)/lib/libwebsockets.a
CURL_DIR = $(FRAMEWORK_BUILD_DIR)/curl
ifneq ($(wildcard $(CURL_DIR)),)
INC_DIRS += $(CURL_DIR)/include
XLDFLAGS += $(CURL_DIR)/lib/libcurl.a
else
# Commands to run if the directory does not exist
XLDFLAGS += -lcurl
endif
XLDFLAGS += -ldl

# UT Control library Requirements
SRC_DIRS += ${TOP_DIR}/src
INC_DIRS += ${TOP_DIR}/include

XCFLAGS += -fPIC -Wall -shared # Flags for compilation
XCFLAGS += -DNDEBUG
XCFLAGS += -DLIBCURL_PATH=\"$(LIBCURL_PATH)\"
# CFLAGS += -DWEBSOCKET_SERVER

MKDIR_P ?= @mkdir -p
Expand All @@ -93,12 +91,14 @@ ifeq ($(TARGET),arm)
#CC := arm-rdk-linux-gnueabi-gcc -mthumb -mfpu=vfp -mcpu=cortex-a9 -mfloat-abi=soft -mabi=aapcs-linux -mno-thumb-interwork -ffixed-r8 -fomit-frame-pointer
# CFLAGS will be overriden by Caller as required
INC_DIRS += $(UT_DIR)/sysroot/usr/include
XLDFLAGS += $(OPENSSL_LIB_DIR)/libssl.a $(OPENSSL_LIB_DIR)/libcrypto.a -ldl
XLDFLAGS += -ldl
LIBCURL_PATH="/usr/lib/libcurl.so.4"
else
#linux case
LIBCURL_PATH="/usr/lib/x86_64-linux-gnu/libcurl.so.4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.4 i don't think is right, the main .so should be a symlink to the right version do an ls -la on the directory. The .4 version of the library will depend on what version of curl is installed and it may not exist but the .so should always. Google the rules for the .so linkage etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response from chatgpt:

Yes, you can pass the path /usr/lib/x86_64-linux-gnu/libcurl.so.4 to your dlopen code and it should work correctly.
Here’s why:
🔹 libcurl.so.4 is a symlink
Your ls -la output confirms:
libcurl.so.4 -> libcurl.so.4.7.0
This means that libcurl.so.4 is a symbolic link to the actual shared library libcurl.so.4.7.0.
When using dlopen() in your code, you can pass:
dlopen("/usr/lib/x86_64-linux-gnu/libcurl.so.4", RTLD_NOW);
This will resolve correctly because the symlink points to a valid ELF shared object file (libcurl.so.4.7.0), which contains the symbols you need.

ls -la /usr/lib/x86_64-linux-gnu/libcurl.*
lrwxrwxrwx 1 root root     16 Dec 11 17:26 /usr/lib/x86_64-linux-gnu/libcurl.so.4 -> libcurl.so.4.7.0
-rw-r--r-- 1 root root 677656 Dec 11 17:26 /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup you've made my point.

libcurl.so is a sym link to the latest installed library

libcurl.so.4 is version 4 of the curl library which may or may not be installed, your checking for a min version of the library, not a max version of it.

so libcurl.so is correct.. libcurl.so.4 is not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My problem here is different servers are giving different output .For ex:

jpn323@ceres ~/workspace/ut-core-1April/scripts (feature/gh#208-print-version)$  find /usr/ -type l -iname "libcurl.so*"
/usr/lib/x86_64-linux-gnu/libcurl.so.4
/usr/lib/x86_64-linux-gnu/libcurl.so
jpn323@janus ~/workspace/ut-control-reduce-size/tests/build/bin (feature/gh79-ut-control-reduce-size)$ find /usr/ -type l -iname "libcurl.so*"
/usr/lib/x86_64-linux-gnu/libcurl.so.4

I have hence come up with a common solution, that will provide me the first symlink when I try to find the library.

# Check if the directory exists
ifneq ($(wildcard $(OPENSSL_LIB_DIR)),)
XLDFLAGS += $(OPENSSL_LIB_DIR)/libssl.a $(OPENSSL_LIB_DIR)/libcrypto.a -ldl
XLDFLAGS += -ldl
else
# Commands to run if the directory does not exist
XLDFLAGS += -lssl -lcrypto
Expand Down Expand Up @@ -150,6 +150,7 @@ list:
@$(ECHOE) ${YELLOW}SRC_DIRS:${NC} ${SRC_DIRS}
@$(ECHOE) ${YELLOW}CFLAGS:${NC} ${CFLAGS}
@$(ECHOE) ${YELLOW}XLDFLAGS:${NC} ${XLDFLAGS}
@$(ECHOE) ${YELLOW}XCFLAGS:${NC} ${XCFLAGS}
@$(ECHOE) ${YELLOW}TARGET_LIB:${NC} ${TARGET_LIB}

clean:
Expand Down
95 changes: 82 additions & 13 deletions src/ut_kvp.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <unistd.h>
#include <assert.h>
#include <curl/curl.h>
#include <dlfcn.h>

/* Application Includes */
#include <ut_kvp.h>
Expand Down Expand Up @@ -62,6 +63,60 @@ static struct fy_node* process_include(const char *filename, int depth, struct f
static void merge_nodes(struct fy_node *mainNode, struct fy_node *includeNode);
static void remove_include_keys(struct fy_node *node);

// Typedefs for curl function pointers
typedef CURL* (*curl_easy_init_t)(void);
typedef CURLcode (*curl_easy_setopt_t)(CURL *, CURLoption, ...);
typedef CURLcode (*curl_easy_perform_t)(CURL *);
typedef CURLcode (*curl_easy_getinfo_t)(CURL *, CURLINFO, ...);
typedef void (*curl_easy_cleanup_t)(CURL *);
typedef const char* (*curl_easy_strerror_t)(CURLcode);

// Function pointers for curl functions
static curl_easy_init_t kvp_curl_easy_init;
static curl_easy_setopt_t kvp_curl_easy_setopt;
static curl_easy_perform_t kvp_curl_easy_perform;
static curl_easy_getinfo_t kvp_curl_easy_getinfo;
static curl_easy_cleanup_t kvp_curl_easy_cleanup;
static curl_easy_strerror_t kvp_curl_easy_strerror;
static void *curl_lib = NULL;

int init_curl_symbols()
{
UT_LOG_DEBUG("Initializing curl symbols from %s", LIBCURL_PATH);
curl_lib = dlopen(LIBCURL_PATH, RTLD_LAZY);
assert(curl_lib != NULL);
if (curl_lib == NULL)
{
UT_LOG_ERROR("dlopen failed for library %s: %s\n", LIBCURL_PATH, dlerror());
return -1;
}

// Load the curl function symbols
kvp_curl_easy_init = (curl_easy_init_t)dlsym(curl_lib, "curl_easy_init");
assert(kvp_curl_easy_init != NULL);
kvp_curl_easy_setopt = (curl_easy_setopt_t)dlsym(curl_lib, "curl_easy_setopt");
assert(kvp_curl_easy_setopt != NULL);
kvp_curl_easy_perform = (curl_easy_perform_t)dlsym(curl_lib, "curl_easy_perform");
assert(kvp_curl_easy_perform != NULL);
kvp_curl_easy_getinfo = (curl_easy_getinfo_t)dlsym(curl_lib, "curl_easy_getinfo");
assert(kvp_curl_easy_getinfo != NULL);
kvp_curl_easy_cleanup = (curl_easy_cleanup_t)dlsym(curl_lib, "curl_easy_cleanup");
assert(kvp_curl_easy_cleanup != NULL);
kvp_curl_easy_strerror = (curl_easy_strerror_t)dlsym(curl_lib, "curl_easy_strerror");
assert(kvp_curl_easy_strerror != NULL);

if ((kvp_curl_easy_init == NULL) || (kvp_curl_easy_setopt == NULL) || (kvp_curl_easy_perform == NULL) ||
(kvp_curl_easy_getinfo == NULL) || (kvp_curl_easy_cleanup ==NULL) || (kvp_curl_easy_strerror == NULL))
{
UT_LOG_ERROR("dlsym failed for one or more symbols\n");
dlclose(curl_lib);
curl_lib = NULL;
return -1;
}

return 0;
}

ut_kvp_instance_t *ut_kvp_createInstance(void)
{
ut_kvp_instance_internal_t *pInstance = malloc(sizeof(ut_kvp_instance_internal_t));
Expand Down Expand Up @@ -136,6 +191,13 @@ ut_kvp_status_t ut_kvp_open(ut_kvp_instance_t *pInstance, char *fileName)
node = process_node(fy_document_root(pInternal->fy_handle), 0);
remove_include_keys(node);

if (curl_lib)
{
// Close the curl library if it was opened
dlclose(curl_lib);
curl_lib = NULL;
}

if (node == NULL)
{
UT_LOG_ERROR("Unable to process node");
Expand Down Expand Up @@ -951,17 +1013,24 @@ static struct fy_node* process_include(const char *filename, int depth, struct f

if (strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0)
{
// URL include
// init curl symbols if not already initialized
if (curl_lib == NULL && init_curl_symbols() != 0)
{
UT_LOG_ERROR("Error: Could not initialize curl symbols\n");
return NULL;
}

// Initialize the memory chunk to store the downloaded data
mChunk.memory = malloc(1);
mChunk.size = 0;

if (!mChunk.memory)
if (mChunk.memory == NULL)
{
UT_LOG_ERROR( "Error: Not enough memory to store curl response\n");
return NULL;
}

CURL *curl = curl_easy_init();
CURL *curl = kvp_curl_easy_init();
if (!curl)
{
UT_LOG_ERROR( "Error: Could not initialize curl\n");
Expand All @@ -970,25 +1039,25 @@ static struct fy_node* process_include(const char *filename, int depth, struct f
}

CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, filename);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&mChunk);
res = curl_easy_perform(curl);
kvp_curl_easy_setopt(curl, CURLOPT_URL, filename);
kvp_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
kvp_curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&mChunk);
res = kvp_curl_easy_perform(curl);
if (res != CURLE_OK)
{
UT_LOG_ERROR( "Error: curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
UT_LOG_ERROR( "Error: curl_easy_perform() failed: %s\n", kvp_curl_easy_strerror(res));
free(mChunk.memory);
curl_easy_cleanup(curl);
kvp_curl_easy_cleanup(curl);
return NULL;
}

long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
kvp_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200)
{
UT_LOG_ERROR( "Error: HTTP request failed with code %ld\n", response_code);
free(mChunk.memory);
curl_easy_cleanup(curl);
kvp_curl_easy_cleanup(curl);
return NULL;
}

Expand All @@ -997,15 +1066,15 @@ static struct fy_node* process_include(const char *filename, int depth, struct f
{
UT_LOG_ERROR("Error: Cannot parse included content\n");
free(mChunk.memory);
curl_easy_cleanup(curl);
kvp_curl_easy_cleanup(curl);
return NULL;
}

process_node(fy_document_root(doc), depth + 1);
// UT_LOG_DEBUG("%s memory chunk = \n%s\n", __FUNCTION__, mChunk.memory);

// free(mChunk.memory); // fy_document_build_from_malloc_string(): The string is expected to have been allocated by malloc(3) and when the document is destroyed it will be automatically freed.
curl_easy_cleanup(curl);
kvp_curl_easy_cleanup(curl);
return fy_document_root(doc);
}
else
Expand Down