c++ How to continuously loop using Curl Multi Interface - c++

im trying to loop continuously using curl multi interface. I have a timer function that needs to continuously loop through 4 urls at once, and go to the next 4, and so on etc.. I have successfully got the curl to poll my handles for its status, but when the handle hits 0, I try to reset the curl handle to loop again using new urls, but its not working. My timer function keeps working as it should, but curl multi stops, and gives me the same curl response using the same 4 urls, even though I try to reset the handles each time. Any help on this please, and thanks.. Below is a snippet of my code..
// Timer function that fires every 30 seconds with 4 different URL's each time
void timerFunction (QString url1,QString url2,QString url3,QString url4)
{
CURLMsg *msg = NULL;
std::string url1_ = url1.toStdString();
std::string url2_ = url2.toStdString();
std::string url3_ = url3.toStdString();
std::string url4_ = url4.toStdString();
CURLM *curlm;
int handle_count;
curlm = curl_multi_init();
CURL *curl1 = NULL;
curl1 = curl_easy_init();
CURL *curl2 = NULL;
curl2 = curl_easy_init();
CURL *curl3 = NULL;
curl3 = curl_easy_init();
CURL *curl4 = NULL;
curl4 = curl_easy_init();
if(curl1 && curl2 && curl3 && curl4)
{
curl_easy_setopt(curl1, CURLOPT_URL, url1_.c_str());
curl_easy_setopt(curl1, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl1);
curl_easy_setopt(curl2, CURLOPT_URL, url2_.c_str());
curl_easy_setopt(curl2, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl2);
curl_easy_setopt(curl3, CURLOPT_URL, url3_.c_str());
curl_easy_setopt(curl3, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl3);
curl_easy_setopt(curl4, CURLOPT_URL, url4_.c_str());
curl_easy_setopt(curl4, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl4);
CURLMcode code;
while(1)
{
code = curl_multi_perform(curlm, &handle_count);
if(handle_count == 0)
{
qDebug() << "Handle is 0, CURL Processing is done -- Repeat Process ";
break;
}
while ((msg = curl_multi_info_read(curlm, &handle_count)))
{
if (msg->msg == CURLMSG_DONE)
{
qDebug() << msg->msg;
curl_easy_reset(curl1);
curl_easy_reset(curl2);
curl_easy_reset(curl3);
curl_easy_reset(curl4);
handle_count = 4;
code = curl_multi_perform(curlm, &handle_count);
}
}
}
}

curl_easy_reset states clearly:
Re-initializes all options previously set on a specified CURL handle
to the default values. This puts back the handle to the same state as
it was in when it was just created with curl_easy_init.
It does not change the following information kept in the handle: live
connections, the Session ID cache, the DNS cache, the cookies and
shares.
What you need to do is use curl_multi_remove_handle and then curl_easy_cleanup for each handle in the loop once you are done with the response.
However you also need to use curl_multi_cleanup after the loop to remove all handles.
Your code would look like this:
// Timer function that fires every 30 seconds with 4 different URL's each time
void timerFunction (QString url1,QString url2,QString url3,QString url4)
{
CURLMsg *msg = NULL;
std::string url1_ = url1.toStdString();
std::string url2_ = url2.toStdString();
std::string url3_ = url3.toStdString();
std::string url4_ = url4.toStdString();
CURLM *curlm;
CURL* eh = NULL;
int still_running = 0, i = 0, msgs_left = 0;
curlm = curl_multi_init();
CURL *curl1 = NULL;
curl1 = curl_easy_init();
CURL *curl2 = NULL;
curl2 = curl_easy_init();
CURL *curl3 = NULL;
curl3 = curl_easy_init();
CURL *curl4 = NULL;
curl4 = curl_easy_init();
if(curl1 && curl2 && curl3 && curl4)
{
curl_easy_setopt(curl1, CURLOPT_URL, url1_.c_str());
curl_easy_setopt(curl1, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl1);
curl_easy_setopt(curl2, CURLOPT_URL, url2_.c_str());
curl_easy_setopt(curl2, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl2);
curl_easy_setopt(curl3, CURLOPT_URL, url3_.c_str());
curl_easy_setopt(curl3, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl3);
curl_easy_setopt(curl4, CURLOPT_URL, url4_.c_str());
curl_easy_setopt(curl4, CURLOPT_WRITEFUNCTION, writeCallback);
curl_multi_add_handle(curlm, curl4);
while(1)
{
curl_multi_perform(curlm, &still_running);
do {
int numfds = 0;
CURLMcode res = curl_multi_wait(curlm, NULL, 0, MAX_WAIT_MSECS, &numfds);
if (res != CURLM_OK) {
// handle error your way
}
curl_multi_perform(curlm, &still_running);
} while (still_running);
while ((msg = curl_multi_info_read(curlm, &msgs_left)))
{
if (msg->msg == CURLMSG_DONE)
{
eh = msg->easy_handle;
qDebug() << msg->msg;
curl_multi_remove_handle(curlm, eh);
curl_easy_cleanup(eh);
}
}
curl_multi_cleanup(cm);
}
}
Have not tested your code, but I modified it so you get an idea of how you should do it.

Related

ByBit Api. Open Active Order. Return "empty param of timestamp". Libcurl c++

Please help!!!! Is there a working example of opening an order in C++
Constantly sending a request to open an order POST https://api.bybit.com/private/linear/order/create
{"api_key":"WTVpIZqOwx2LGYY3TB","order_type":"Market","qty":5,"side":"Buy","symbol":"MATICUSDT","time_in_force":"GoodTillCancel","timestamp":1652444871610,"sign":"433b79f452a6c43f3b507df4b5cee84314c7aae584546a889cde7d750ac2f4a6"}
I get an error
{"ret_code":10001,"ret_msg":"empty param of timestamp","ext_code":"","ext_info":"","result":null,"time_now":"1652444872.324646"
And no one can explain why
the code itself
int main(int, char **)
{
CURL *curl;
CURLcode res;
unsigned long long timestamp = chrono::duration_cast<chrono::milliseconds>(chrono::_V2::system_clock::now().time_since_epoch()).count();
string api_key = "WT***************3TB";
string secret_key = "Ik**************4vE";
string reqParam = "api_key=" + api_key + "&order_type=Market&qty=5&side=Buy&symbol=MATICUSDT&time_in_force=GoodTillCancel&timestamp=" + to_string(timestamp);
string sign = hmacEncode(reqParam, secret_key);
string json = "{\"api_key\":\"" + api_key + "\",\"side\"=\"Buy\",\"symbol\"=\"MATICUSDT\",\"order_type\":\"Market\",\"qty\":2,\"time_in_force\":\"GoodTillCancel\",\"timestamp\":" + to_string(timestamp) + " ,\"sign\":\"" + sign + "\"}";
cout << json << endl;
curl = curl_easy_init();
if (curl)
{
// set params
curl_easy_setopt(curl, CURLOPT_POST, 1); // post req
curl_easy_setopt(curl, CURLOPT_URL, "https://api.bybit.com/private/linear/order/create"); // url
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
// Header "Content-Type: application/json"
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
https://github.com/alex290/bybitorder-api/blob/master/src/main.cpp
Everything solved the problem. Here is the working code
int main(int, char **)
{
CURL *curl;
CURLcode res;
unsigned long long timestamp = chrono::duration_cast<chrono::milliseconds>(chrono::_V2::system_clock::now().time_since_epoch()).count();
string api_key = "WT***************3TB";
string secret_key = "Ik**************4vE";
string reqParam = "api_key=" + api_key + "&close_on_trigger=false&order_type=Market&position_idx=0&qty=5&reduce_only=false&side=Buy&symbol=MATICUSDT&time_in_force=GoodTillCancel&timestamp=" + to_string(timestamp);
string sign = hmacEncode(reqParam, secret_key);
reqParam = reqParam + "&sign=" + sign;
string urlStr = "https://api.bybit.com/private/linear/order/create?" + reqParam;
cout << urlStr << endl;
curl = curl_easy_init();
if (curl)
{
// set params
curl_easy_setopt(curl, CURLOPT_POST, 1); // post req
curl_easy_setopt(curl, CURLOPT_URL, urlStr.c_str()); // url
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
// Header "Content-Type: application/json"
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
I see some strange things. Your wrong JSON in the code:
"\"side\"=\"Buy\",\"symbol\"=\"MATICUSDT\"
It is not consistent with the dumped JSON
"side":"Buy","symbol":"MATICUSDT".
Your code has space after the timestamp, the dumped JSON has no spaces. And the parameter order is different.

I try to implement curl script for request to server but it is not working

I have a curl script:
curl -k -H "Content-Type: application/txt" -X POST --data-binary "#name_file.txt" -g "https://ya.com/file.txt" > .\out.txt
I can use it via console ant it works good.
I implement this script in visual studio on C++:
auto curl = curl_easy_init();
if (curl)
{
FILE* fp = fopen(path_to_file.c_str(), "wb");
curl_easy_setopt(curl, CURLOPT_URL, "https://ya.com/file.txt");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Content-Type: application/txt");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); // - H
std::string data_for_send = data_for_send_arr.c_str();
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data_for_send.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_for_send.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackfunction);
res = curl_easy_perform(curl);
if (res != CURLE_OK) AfxMessageBox(_T("error"));
curl_easy_cleanup(curl);
curl_global_cleanup();
fclose(fp);
}
size_t callbackfunction(void *ptr, size_t size, size_t nmemb, void* userdata)
{
FILE* stream = (FILE*)userdata;
if (!stream)
{
printf("!!! No stream\n");
return 0;
}
size_t written = fwrite((FILE*)ptr, size, nmemb, stream);
return written;
}
i also i need to tell that at one moment i use async call:
async(func_curl_1, data_1);
async(func_curl_2, data_2);
each function create curl and do request for server at the same time.
but this script do not work. it work one time from seven request
server returned for me empty file or broken file.
i do not know why...
try to add in your settings CURLOPT_VERBOSE
i.e.
/* ask libcurl to show us the verbose output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
and investigate output

libcurl simple C file downloader example immediately returns

I tried compiling both the examples on this question: Download file using libcurl in C/C++
Here's one of them:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
FILE *fp;
CURLcode res;
char *url = "http://stackoverflow.com";
char outfilename[FILENAME_MAX] = "page.html";
curl = curl_easy_init();
if (curl)
{
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
the problem is that this example, when run, immediately returns and I get a blank file. Why? I modified to
if (curl)
{
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
} else {
printf("error\n");
}
but I see no error. I tried compiling in both C++ and C, I get the same result on both.
I had the same issue and I fixed it by:
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
According to https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html, true tells the library to follow HTTP location.

C++: How can I Send binary data(protobuf data) using HTTP post request through a curl call

I am trying trying to make a POST request on a url with protobuf data. I don't know how/ where to add binary data. Below is my C++ program.
"
void sendContent()
{
using namespace std;
int Error = 0;
//CString str;
CURL* curl;
CURLcode res;
struct curl_slist *headerlist = NULL;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
//Set URL to recevie POST
curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_HEADER, true);
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
}"
You should set the data pointer by curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);. In the meantime, you should set the data size by curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);.
You can find the libcurl post example in there.
And I copy the program below.
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if(curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
/* Now specify the POST data */
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);
/* binary data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Fixing your original suggestion would probably make it something like this (based on the simplepost example from the libcurl web site):
#include <curl/curl.h>
int binarypost(char *binaryptr, long binarysize)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *headerlist = NULL;
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, binaryptr);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, binarysize);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return (int)res;
}

How do I kill the popup?

If you edit the following code to have valid certificate paths and a url that requires client certificates and then compile it with clang++ -lcurl curl.cpp on OS X (I'm using El Cap, but I think Mavericks or later behave the same way), and run the executable, you get a popup (shown below) from OS X asking if you want to allow the executable to use a private key in your keychain. This is annoying to users that know what's going on (internally curl on OS X uses the OS X security framework to load the client cert) but it's frightening for users who don't know what's happening because they think that the program is trying to access a private key in their keychain (as an aside this is an example of terrible UX from Apple as the popup message is a complete red herring).
The curl command line tool doesn't produce a popup, so either there is a lower level API I could use or it's because the executable is signed. The real program I'm trying to add this feature to is often distributed as source code so signing the executable isn't an ideal approach, as I can't distribute the signing keys or they'll be revoked. Does anyone know how I can prevent the popup programmatically?
#include <curl/curl.h>
#include <string>
using namespace std;
static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
string *responseData = (string *) userData;
responseData->append((const char *) buffer, size * nmemb);
return size * nmemb;
}
void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.dev/v1/check.json");
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
*chunk = curl_slist_append(NULL, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
curl_easy_setopt(curl, CURLOPT_SSLCERT, "/path/to/client_cert.p12");
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "P12");
curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, "1234");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca.crt");
}
int main(){
CURL* curl = curl_easy_init();
struct curl_slist *chunk = NULL;
string responseData;
long responseCode;
string bodyJsonString = "{\"version\": 1}";
prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
if (responseCode != 200) {
fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
}
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
}
This is how I solved this problem (thanks to the Phusion folks for letting me tinker on this):
#include <curl/curl.h>
#include <string>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
using namespace std;
const char* cert_label = "Name of the certificate as it appears in keychain access";
const char* domain = "https://example.dev/v1/check.json";
const char* ca_path = "/path/to/ca.crt";
const char* cert_path = "/path/to/client_cert.p12";
const char* cert_pw = "1234";
static OSStatus LookupKeychainItem(const char *label,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
if(kSecClassIdentity != NULL) {
CFTypeRef keys[4];
CFTypeRef values[4];
CFDictionaryRef query_dict;
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
kCFStringEncodingUTF8);
/* Set up our search criteria and expected results: */
values[0] = kSecClassIdentity; /* we want a certificate and a key */
keys[0] = kSecClass;
values[1] = kCFBooleanTrue; /* we need a reference */
keys[1] = kSecReturnRef;
values[2] = kSecMatchLimitOne; /* one is enough, thanks */
keys[2] = kSecMatchLimit;
/* identity searches need a SecPolicyRef in order to work */
values[3] = SecPolicyCreateSSL(false, label_cf);
keys[3] = kSecMatchPolicy;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
(const void **)values, 4L,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(values[3]);
CFRelease(label_cf);
/* Do we have a match? */
status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
CFRelease(query_dict);
}
return status;
}
SecAccessRef createAccess()
{
SecAccessRef access=NULL;
if (SecAccessCreate(CFStringCreateWithCString(NULL, cert_label, kCFStringEncodingUTF8), NULL, &access)){
printf("SecAccessCreate failed\n");
return NULL;
}
return access;
}
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
const char *cPassword,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8 *)cPath, strlen(cPath), false);
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
cPassword, kCFStringEncodingUTF8) : NULL;
CFDataRef pkcs_data = NULL;
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
NULL, NULL, &status)) {
SecAccessRef access = createAccess();
const void *cKeys[] = {kSecImportExportPassphrase,kSecImportExportAccess};
//kSecTrustSettingsKeyUseAny
const void *cValues[] = {password,access};
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
2L, NULL, NULL);
CFArrayRef items = NULL;
/* Here we go: */
status = SecPKCS12Import(pkcs_data, options, &items);
if(items)
CFRelease(items);
CFRelease(options);
CFRelease(pkcs_data);
}
if(password)
CFRelease(password);
CFRelease(pkcs_url);
return status;
}
static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
string *responseData = (string *) userData;
responseData->append((const char *) buffer, size * nmemb);
return size * nmemb;
}
void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, domain);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
*chunk = curl_slist_append(NULL, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
curl_easy_setopt(curl, CURLOPT_SSLCERT, cert_label);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(curl, CURLOPT_CAINFO, ca_path);
}
void killKey(){
SecIdentityRef id = NULL;
if (LookupKeychainItem(cert_label,&id) != errSecItemNotFound){
CFArrayRef itemList = CFArrayCreate(NULL, (const void **)&id, 1, NULL);
const void *keys2[] = { kSecClass, kSecMatchItemList, kSecMatchLimit };
const void *values2[] = { kSecClassIdentity, itemList, kSecMatchLimitAll };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys2, values2, 3, NULL, NULL);
OSStatus oserr = SecItemDelete(dict);
if (oserr) {
CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
printf("Removing Passenger Cert from keychain failed: %s Please remove the private key from the certificate labeled %s in your keychain.", CFStringGetCStringPtr(str,kCFStringEncodingUTF8), cert_label);
CFRelease(str);
}
CFRelease(dict);
CFRelease(itemList);
}
}
void preAuthKey(){
SecIdentityRef id = NULL;
if(LookupKeychainItem(cert_label,&id) == errSecItemNotFound){
OSStatus status = SecKeychainSetUserInteractionAllowed(false);
if(status != errSecSuccess){
printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
}
CopyIdentityFromPKCS12File("/path/to/client_cert.p12","1234",&id);
status = SecKeychainSetUserInteractionAllowed(true);
if(status != errSecSuccess){
printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
}
}
}
int main(){
preAuthKey();
CURL* curl = curl_easy_init();
struct curl_slist *chunk = NULL;
string responseData;
long responseCode;
string bodyJsonString = "{\"version\": 1}";
prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
if (responseCode != 200) {
fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
}
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
killKey();
}