Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Commit

Permalink
1.5.0 (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
hroederld authored Jul 26, 2019
1 parent 9ce5cee commit 14dc8ca
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 75 deletions.
28 changes: 0 additions & 28 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,38 +48,10 @@ jobs:
- store_artifacts:
path: /tmp/artifacts

build-test-windows:
docker:
- image: ubuntu:18.04
steps:
- checkout
- run:
name: Add Wine
command: dpkg --add-architecture i386 && apt-get update -y && apt-get install -y wine-development wine32 wine64
- run:
name: Install build dependencies
command: apt-get install -y unzip wget make mingw-w64
- run:
name: Download Windows Curl
command: wget -O mingw.zip https://curl.haxx.se/windows/dl-7.62.0_1/curl-7.62.0_1-win64-mingw.zip && unzip mingw.zip
- run:
name: Download Windows SSL
command: wget -O openssl.zip https://bintray.com/vszakats/generic/download_file?file_path=openssl-1.1.1a-win64-mingw.zip && unzip openssl.zip
- run:
name: Copy Runtime Dependencies
command: cp openssl-1.1.1a-win64-mingw/libcrypto-1_1-x64.dll . && cp openssl-1.1.1a-win64-mingw/libssl-1_1-x64.dll . && cp curl-7.62.0-win64-mingw/bin/libcurl-x64.dll .
- run:
name: Cross Compile
command: make ALTBUILD=mingw
- run:
name: Test Emulated
command: wine ./test

workflows:
version: 2
build_and_test_all:
jobs:
- build-test-linux-recent
- build-test-linux-historical
- build-test-osx
- build-test-windows
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to the LaunchDarkly C SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).

## [1.5.0] - 2019-07-26
### Added
- Added the `LDUserFree` function. This can be used to free a user object *before* it has been passed to the client
### Fixed
- A leak of HTTP headers set for requests to LaunchDarkly
- A leak of the in memory flag store when `LDClientIdentify` is called. This was introduced in `1.2.0`
- A leak of a structure when events are flushed but no events need to be sent

## [1.4.0] - 2019-07-03
### Added
- Added the `LDConfigSetVerifyPeer` configuration option. This option allows disabling certificate verification, which may be useful for testing, or in unfortunate networking configurations. Note that certificate verification should not be disabled unless it is essential, as it makes the SDK vulnerable to man-in-the-middle attacks. (Thanks, [mstrater](https://github.com/mstrater)!)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ LaunchDarkly Client-Side SDK for C/C++
===================================

[![CircleCI](https://circleci.com/gh/launchdarkly/c-client-sdk.svg?style=svg)](https://circleci.com/gh/launchdarkly/c-client-sdk)
[![AzureCI](https://launchdarkly.visualstudio.com/c-client-sdk-private/_apis/build/status/c-client-private-CI?branchName=master)](https://launchdarkly.visualstudio.com/c-client-sdk-private/_build/latest?definitionId=18&branchName=master)

The LaunchDarkly Client-Side SDK for C/C++ is designed primarily for use in desktop and embedded systems applications. It follows the client-side LaunchDarkly model for single-user contexts (much like our mobile or JavaScript SDKs). It is not intended for use in multi-user systems such as web servers and applications.

Expand Down
5 changes: 4 additions & 1 deletion ldapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/** @brief The current SDK version string. This value adheres to semantic
* versioning and is included in the HTTP user agent sent to LaunchDarkly. */
#define LD_SDK_VERSION "1.4.0"
#define LD_SDK_VERSION "1.5.0"

/** @brief Used to ensure only intended symbols are exported in the binaries */
#ifdef DOXYGEN_SHOULD_SKIP_THIS
Expand Down Expand Up @@ -274,6 +274,9 @@ LD_EXPORT(struct LDClient_i *) LDClientInit(LDConfig *const config,
* device specific ID cannot be obtained then a random fallback is generated. */
LD_EXPORT(LDUser *) LDUserNew(const char *const key);

/** @brief Free a user object */
LD_EXPORT(void) LDUserFree(LDUser *const user);

/** @brief Mark the user as anonymous. */
LD_EXPORT(void) LDUserSetAnonymous(LDUser *const user, const bool anon);

Expand Down
5 changes: 3 additions & 2 deletions ldclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,15 @@ LDClientIdentify(LDClient *const client, LDUser *const user)
LDi_wrlock(&globalContext.sharedUserLock);

if (user != globalContext.sharedUser) {
LDi_freeuser(globalContext.sharedUser);
LDUserFree(globalContext.sharedUser);
}

globalContext.sharedUser = user;

HASH_ITER(hh, globalContext.clientTable, clientIter, tmp) {
LDi_wrlock(&clientIter->clientLock);

LDi_freehash(clientIter->allFlags);
clientIter->allFlags = NULL;

if (clientIter->status == LDStatusInitialized) {
Expand Down Expand Up @@ -488,7 +489,7 @@ LDClientClose(LDClient *const client)
clientCloseIsolated(clientIter);
}

LDi_freeuser(globalContext.sharedUser);
LDUserFree(globalContext.sharedUser);
LDConfigFree(globalContext.sharedConfig);

globalContext.sharedConfig = NULL;
Expand Down
1 change: 1 addition & 0 deletions ldclientapi.def
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ EXPORTS
LDClientGetForMobileKey

LDUserNew
LDUserFree
LDUserSetAnonymous
LDUserSetIP
LDUserSetFirstName
Expand Down
18 changes: 10 additions & 8 deletions ldevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,17 +296,19 @@ LDi_geteventdata(LDClient *const client)
collectSummary(client);

LDi_wrlock(&client->eventLock);

if (client->numEvents == 0) {
LDi_wrunlock(&client->eventLock);
return NULL;
}

cJSON *const events = client->eventArray;
client->eventArray = cJSON_CreateArray();
const int hadevents = client->numEvents;
client->numEvents = 0;

LDi_wrunlock(&client->eventLock);

if (hadevents) {
char *const data = cJSON_PrintUnformatted(events);
cJSON_Delete(events);
return data;
} else {
return NULL;
}
char *const data = cJSON_PrintUnformatted(events);
cJSON_Delete(events);
return data;
}
2 changes: 0 additions & 2 deletions ldinternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,6 @@ unsigned char * LDi_base64_encode(const unsigned char *src, size_t len,
void LDi_freehash(LDNode *hash);
void LDi_freenode(LDNode *node);

void LDi_freeuser(LDUser *user);

char *LDi_hashtostring(const LDNode *hash, bool versioned);
cJSON *LDi_hashtojson(const LDNode *hash);
cJSON *LDi_arraytojson(const LDNode *hash);
Expand Down
89 changes: 59 additions & 30 deletions ldnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ prepareShared(const char *const url, const LDConfig *const config,
void *const headerdata, WriteCB datacb, void *const data,
const LDClient *const client)
{
struct curl_slist *headers = NULL, *headerstmp = NULL;
CURL *const curl = curl_easy_init();

if (!curl) {
Expand All @@ -119,14 +120,15 @@ prepareShared(const char *const url, const LDConfig *const config,
LDi_log(LD_LOG_CRITICAL, "snprintf during Authorization header creation failed"); goto error;
}

struct curl_slist *headers = NULL;
if (!(headers = curl_slist_append(headers, headerauth))) {
if (!(headerstmp = curl_slist_append(headers, headerauth))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headerauth"); goto error;
}
headers = headerstmp;

if (!(headers = curl_slist_append(headers, LD_USER_AGENT_HEADER))) {
if (!(headerstmp = curl_slist_append(headers, LD_USER_AGENT_HEADER))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headeragent"); goto error;
}
headers = headerstmp;

if (curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headercb) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_HEADERFUNCTION failed"); goto error;
Expand Down Expand Up @@ -159,7 +161,8 @@ prepareShared(const char *const url, const LDConfig *const config,
return true;

error:
if (curl) { curl_easy_cleanup(curl); }
curl_easy_cleanup(curl);
curl_slist_free_all(headers);

return false;
}
Expand Down Expand Up @@ -215,7 +218,7 @@ void
LDi_readstream(LDClient *const client, int *response, int cbdata(LDClient *, const char *), void cbhandle(LDClient *, int))
{
struct MemoryStruct headers; struct streamdata streamdata; struct cbhandlecontext handledata;
CURL *curl = NULL; struct curl_slist *headerlist = NULL;
CURL *curl = NULL; struct curl_slist *headerlist = NULL, *headertmp = NULL;

handledata.client = client; handledata.cb = cbhandle;

Expand Down Expand Up @@ -281,49 +284,50 @@ LDi_readstream(LDClient *const client, int *response, int cbdata(LDClient *, con
if (client->shared->sharedConfig->useReport) {
if (curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "REPORT") != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_CUSTOMREQUEST failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

const char* const headermime = "Content-Type: application/json";
if (!(headerlist = curl_slist_append(headerlist, headermime))) {
if (!(headertmp = curl_slist_append(headerlist, headermime))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headermime");
curl_easy_cleanup(curl); return;
goto cleanup;
}
headerlist = headertmp;

if (curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonuser) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_POSTFIELDS failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}
}

if (curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, SocketCallback) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_OPENSOCKETFUNCTION failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &handledata) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_OPENSOCKETDATA failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_HTTPHEADER failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_NOPROGRESS failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressinspector) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_PROGRESSFUNCTION failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *)&streamdata) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_PROGRESSDATA failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

LDi_log(LD_LOG_INFO, "connecting to stream %s", url);
Expand All @@ -337,7 +341,11 @@ LDi_readstream(LDClient *const client, int *response, int cbdata(LDClient *, con
*response = -1;
}

free(streamdata.mem.memory); free(headers.memory);
cleanup:
free(streamdata.mem.memory);
free(headers.memory);

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl);
}
Expand All @@ -346,7 +354,8 @@ char *
LDi_fetchfeaturemap(LDClient *const client, int *response)
{
struct MemoryStruct headers, data;
CURL *curl = NULL; struct curl_slist *headerlist = NULL;
CURL *curl = NULL;
struct curl_slist *headerlist = NULL, *headertmp = NULL;

memset(&headers, 0, sizeof(headers)); memset(&data, 0, sizeof(data));

Expand Down Expand Up @@ -407,24 +416,25 @@ LDi_fetchfeaturemap(LDClient *const client, int *response)
if (client->shared->sharedConfig->useReport) {
if (curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "REPORT") != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_CUSTOMREQUEST failed");
curl_easy_cleanup(curl); return NULL;
goto error;
}

const char *const headermime = "Content-Type: application/json";
if (!(headerlist = curl_slist_append(headerlist, headermime))) {
if (!(headertmp = curl_slist_append(headerlist, headermime))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headermime");
curl_easy_cleanup(curl); return NULL;
goto error;
}
headerlist = headertmp;

if (curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonuser) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_POSTFIELDS failed");
curl_easy_cleanup(curl); return NULL;
goto error;
}
}

if (curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_HTTPHEADER failed");
curl_easy_cleanup(curl); return NULL;
goto error;
}

if (curl_easy_perform(curl) == CURLE_OK) {
Expand All @@ -437,16 +447,29 @@ LDi_fetchfeaturemap(LDClient *const client, int *response)

free(headers.memory);

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl);

return data.memory;

error:
free(data.memory);
free(headers.memory);

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl);

return NULL;
}

void
LDi_sendevents(LDClient *const client, const char *eventdata, int *response)
{
struct MemoryStruct headers, data;
CURL *curl = NULL; struct curl_slist *headerlist = NULL;
CURL *curl = NULL;
struct curl_slist *headerlist = NULL, *headertmp = NULL;

memset(&headers, 0, sizeof(headers)); memset(&data, 0, sizeof(data));

Expand All @@ -463,25 +486,27 @@ LDi_sendevents(LDClient *const client, const char *eventdata, int *response)
}

const char *const headermime = "Content-Type: application/json";
if (!(headerlist = curl_slist_append(headerlist, headermime))) {
if (!(headertmp = curl_slist_append(headerlist, headermime))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headermime");
curl_easy_cleanup(curl); return;
goto cleanup;
}
headerlist = headertmp;

const char *const headerschema = "X-LaunchDarkly-Event-Schema: 3";
if (!(headerlist = curl_slist_append(headerlist, headerschema))) {
if (!(headertmp = curl_slist_append(headerlist, headerschema))) {
LDi_log(LD_LOG_CRITICAL, "curl_slist_append failed for headerschema");
curl_easy_cleanup(curl); return;
goto cleanup;
}
headerlist = headertmp;

if (curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_HTTPHEADER failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_setopt(curl, CURLOPT_POSTFIELDS, eventdata) != CURLE_OK) {
LDi_log(LD_LOG_CRITICAL, "curl_easy_setopt CURLOPT_POSTFIELDS failed");
curl_easy_cleanup(curl); return;
goto cleanup;
}

if (curl_easy_perform(curl) == CURLE_OK) {
Expand All @@ -492,7 +517,11 @@ LDi_sendevents(LDClient *const client, const char *eventdata, int *response)
*response = -1;
}

free(data.memory); free(headers.memory);
cleanup:
free(data.memory);
free(headers.memory);

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl);
}
2 changes: 1 addition & 1 deletion lduser.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ LDUserNew(const char *const key)
}

void
LDi_freeuser(LDUser *const user)
LDUserFree(LDUser *const user)
{
if (!user) { return; }
LDFree(user->key);
Expand Down
Loading

0 comments on commit 14dc8ca

Please sign in to comment.