json conversion error c++ IsString failed - c++

I have data in a JSON object that I can't seem to get to.
Error:
> testGetprice3.o: testGetprice3.cpp:71: int getData(): Assertion
> `document["success"].IsString()' failed.
I have tried switching the datatypes, it only errors.
How do I correctly access my JSON object data?
#include "rapidjson/include/rapidjson/document.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <unordered_map>
#include <string>
using namespace rapidjson;
struct myData
{
std::fstream *file;
std::string *str;
};
size_t write_data(void *ptr, size_t size, size_t nmemb, myData *data)
{
size_t numBytes = size * nmemb;
if (data->file)
data->file->write((char*)ptr, numBytes);
if (data->str)
*data->str += std::string((char*)ptr, numBytes);
return numBytes;
}
//function to get coin data and perform analysis
int getData()
{
int count = 0;
//begin non terminating loop
while(true)
{
count++;
CURL *curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=155");
std::fstream file("/home/coinz/cryptsy/myfile.txt", std::ios_base::out | std::ios_base::ate);
std::string json;
myData data;
data.file = &file;
data.str = &json;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
{
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
else
{
file << std::endl;
//begin deserialization
Document document;
document.Parse(json.c_str());
assert(document.HasMember("success"));
assert(document["success"].IsString());
//std::cout << "The Last Traded Price is = " << document["lasttradeprice"].GetString() << std::endl;
}
/* always cleanup */
curl_easy_cleanup(curl);
}
//timer for URL request. *ADUJST ME AS DESIRED*
usleep(10000000);
}
return 0;
}
//Le Main
int main(void)
{
getData();
}

Looking at your JSON data, the success member is an int (as it is not surrounded by quote marks).
More info on JSON types can be found here: http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example
If the success member was a string, the JSON data would look like this: {"success":"1",...
Therefore when you call assert(document["success"].IsString()) it causes the error, as the success member is not a string, but an int.
Since the success member is an int, change the assertion to test whether it's an int - assert(document["success"].IsInt())

You stated you changed datatypes, but did not state which ones you tried. From the URL you are using, success is being returned as "success":1, which is an int.
Change:
assert(document["success"].IsString());
to:
assert(document["success"].IsInt());

Related

Capturing the output from libcurl in a std::string in c++ under Windows

I want to capture the libcurl error output that is normally sent to stderr into a std::string instead.
This is the code I have come up with so far:
#include <windows.h>
#include <streambuf>
#include <iostream>
#include <io.h>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <string>
#include "curl\curl.h"
std::string data; //will hold the url's contents
// callback function for curl
size_t writeCallback(char* buf, size_t size, size_t nmemb, void* up)
{ //callback must have this declaration
//buf is a pointer to the data that curl has for us
//size*nmemb is the size of the buffer
for (int c = 0; c < size * nmemb; c++)
{
data.push_back(buf[c]);
}
return size * nmemb; //tell curl how many bytes we handled
}
int main()
{
CURL* curl; //our curl object
curl_global_init(CURL_GLOBAL_ALL); //pretty obvious
curl = curl_easy_init();
CURLcode res;
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_URL, "http://ww.example.com/path");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //tell curl to output its progress
int old;
FILE* DataFile;
old = _dup(2); // redirect stderr to "old"
if (fopen_s(&DataFile, "data", "w") != 0)
{
puts("Can't open file 'Datafile'\n");
exit(1);
}
// stderr now refers to file "Datafile"
if (-1 == _dup2(_fileno(DataFile), 2))
{
perror("Can't _dup2 stderr");
exit(1);
}
res = curl_easy_perform(curl);
// Flush stderr stream buffer so it goes to correct file
fflush(stderr);
fclose(DataFile);
// Restore original stderr
_dup2(old, 2);
curl_easy_cleanup(curl);
curl_global_cleanup();
std::ifstream filetoread(DataFile);
if (filetoread)
{
// get length of file:
filetoread.seekg(0, filetoread.end);
int length = filetoread.tellg();
filetoread.seekg(0, filetoread.beg);
char* buffer = new (std::nothrow) char[length];
if (buffer == nullptr)
{
std::cout << "Error allocating buffer.\nvariable 'length' is: " << length << std::endl;
return 0;
}
std::cout << "Reading " << length << " characters... ";
// read data as a block:
filetoread.read(buffer, length);
if (filetoread)
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << filetoread.gcount() << " could be read";
filetoread.close();
// ...buffer contains the entire file...
std::string buffertext(buffer);
delete[] buffer;
}
_flushall();
}
It seems to me that the file Datafile is empty since the variable length is -1. Can anybody help with this code? The examples in redirect stdout/stderr to a string haven't proved to be a solution to my question so far.
I'd use the FUNCTION/DATA pairs in a wrapper class to be able to create event handlers that are called automatically for the events you'd like to handle. Here's an example with comments in the code:
#include "curl/curl.h"
#include <iostream>
#include <memory>
#include <stdexcept>
#include <utility>
// A simple wrapper class for the C functions in libcurl
class EasyCurly {
public:
// default constructor
EasyCurly() : handle(curl_easy_init()) {
if(handle == nullptr) throw std::runtime_error("curl_easy_init failed");
// Set "this" as data pointer in callbacks to be able to make a call to the
// correct EasyCurly object. There are a lot more callback functions you
// could add here if you need them.
setopt(CURLOPT_WRITEDATA, this);
setopt(CURLOPT_DEBUGDATA, this);
setopt(CURLOPT_XFERINFODATA, this);
// Setup of proxy/callback functions. There should be one for each function
// above.
setopt(CURLOPT_WRITEFUNCTION, write_callback);
setopt(CURLOPT_DEBUGFUNCTION, debug_callback);
setopt(CURLOPT_XFERINFOFUNCTION, progress_callback);
// some default options, remove those you usually don't want
setopt(CURLOPT_NOPROGRESS, 0); // turn on progress callbacks
setopt(CURLOPT_FOLLOWLOCATION, 1L); // redirects
setopt(CURLOPT_HTTPPROXYTUNNEL, 1L); // corp. proxies etc.
// setopt(CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
setopt(CURLOPT_VERBOSE, 1L); // we want it all
}
// copy constructor
EasyCurly(const EasyCurly& other) : handle(curl_easy_duphandle(other.handle)) {
if(handle == nullptr) throw std::runtime_error("curl_easy_duphandle failed");
// State information is not shared when using curl_easy_duphandle. Only the
// options you've set (so you can create one CURL object, set its options and
// then use as a template for other objects. The document and debug data are
// therefor also not copied.
}
// move constructor
EasyCurly(EasyCurly&& other) :
handle(std::exchange(other.handle, nullptr)),
m_document(std::move(other.m_document)), m_debug(std::move(other.m_debug)) {}
// copy assignment
EasyCurly& operator=(const EasyCurly& other) {
CURL* tmp_handle = curl_easy_duphandle(other.handle);
if(handle == nullptr) throw std::runtime_error("curl_easy_duphandle failed");
// dup succeeded, now destroy any handle we might have and copy the tmp
curl_easy_cleanup(handle);
handle = tmp_handle;
return *this;
}
// move assignment
EasyCurly& operator=(EasyCurly&& other) {
std::swap(handle, other.handle);
std::swap(m_document, other.m_document);
std::swap(m_debug, other.m_debug);
return *this;
}
virtual ~EasyCurly() { curl_easy_cleanup(handle); }
// To be able to use an instance of EasyCurly with C interfaces if you don't add
// a function to this class for it, this operator will help
operator CURL*() { return handle; }
// generic curl_easy_setopt wrapper
template<typename T>
CURLcode setopt(CURLoption option, T v) {
return curl_easy_setopt(handle, option, v);
}
// perform by supplying url
CURLcode perform(std::string_view url) {
setopt(CURLOPT_URL, url.data());
return perform();
}
// perform with a previously supplied url
CURLcode perform() {
m_document.clear();
m_debug.clear();
return curl_easy_perform(handle);
}
// get collected data
std::string const& document() const { return m_document; }
std::string const& debug() const { return m_debug; }
// callbacks from proxy functions
virtual size_t on_write(char* ptr, size_t total_size) {
m_document.insert(m_document.end(), ptr, ptr + total_size);
// std::cout << "<write_callback> size " << total_size << "\n";
return total_size;
}
virtual int on_debug(curl_infotype /*type*/, char* data, size_t size) {
m_debug.insert(m_debug.end(), data, data + size);
// std::cout << "<debug>\n";
return 0; // must return 0
}
// override this to make a progress bar ...
virtual int on_progress(curl_off_t /*dltotal*/, curl_off_t /*dlnow*/,
curl_off_t /*ultotal*/, curl_off_t /*ulnow*/) {
// std::cout << "<progress>\n";
return 0;
}
private:
// a private class to initialize and cleanup once
class CurlGlobalInit {
public:
CurlGlobalInit() {
// std::cout << "CurlGlobalInit\n";
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
if(res) throw std::runtime_error("curl_global_init failed");
}
~CurlGlobalInit() {
// std::cout << "~CurlGlobalInit\n";
curl_global_cleanup();
}
};
// callback functions - has to be static to work with the C interface in curl
// use the data pointer (this) that we set in the constructor and cast it back
// to a EasyCurly* and call the event handler in the correct object.
static size_t write_callback(char* ptr, size_t size, size_t nmemb,
void* userdata) {
EasyCurly* ecurly = static_cast<EasyCurly*>(userdata);
return ecurly->on_write(ptr, nmemb * size); // size==1 really
}
static int debug_callback(CURL* /*handle*/, curl_infotype type, char* data,
size_t size, void* userptr) {
EasyCurly* ecurly = static_cast<EasyCurly*>(userptr);
return ecurly->on_debug(type, data, size);
}
static int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow) {
EasyCurly* ecurly = static_cast<EasyCurly*>(clientp);
return ecurly->on_progress(dltotal, dlnow, ultotal, ulnow);
}
// resources
CURL* handle;
std::string m_document{};
std::string m_debug{};
// a static initializer object
static CurlGlobalInit setup_and_teardown;
};
// This must be defined in your .cpp file if you use this and split it into header
// and implementation parts.
EasyCurly::CurlGlobalInit EasyCurly::setup_and_teardown{};
// end of wrapper class
// --------------------------------------------------------------------------
// with that in place, the rest becomes something like this:
int main() {
EasyCurly curl; // our curl object
CURLcode res = curl.perform("http://www.google.com/");
std::cout << "result: " << res << "\n";
std::cout << "--- document size " << curl.document().size() << " captured ---\n"
<< curl.document() << "---------\n\n";
std::cout << "--- debug size " << curl.debug().size() << " captured ---\n"
<< curl.debug() << "---------\n";
}

error: 'ios_base' has not been declared

I am using libcurl to download serialized code and bust it open but, I get an error that looks like fstream is missing but it is very much included. I looked around but very little on the error.
Below is the error and code.
What did miss?
compile error output
g++ -g testGetprice2.cpp -o testGetprice2.o -std=gnu++11 -lcurl
testGetprice2.cpp: In function 'int getData()':
testGetprice2.cpp:45:56: error: 'ios_base' has not been declared
testGetprice2.cpp:45:72: error: 'ios_base' has not been declared
code:
#include "rapidjson/include/rapidjson/document.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <unordered_map>
#include <string>
using namespace rapidjson;
struct myData
{
std::fstream *file;
std::string *str;
};
size_t write_data(void *ptr, size_t size, size_t nmemb, myData *data)
{
size_t numBytes = size * nmemb;
if (data->file)
data->file->write((char*)ptr, numBytes);
if (data->str)
*data->str += std::string((char*)ptr, numBytes);
return numBytes;
}
//function to get coin data and perform analysis
int getData()
{
int count = 0;
//begin non terminating loop
while(true)
{
count++;
CURL *curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=155");
std::fstream file("/home/coinz/cryptsy/myfile.txt", ios_base::out | ios_base::ate);
std::string json;
myData data;
data.file = &file;
data.str = &json;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
{
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
else
{
file << std::endl;
//begin deserialization
Document document;
document.Parse(json.c_str());
assert(document.HasMember("lasttradeprice"));
assert(document["hello"].IsString());
std::cout << "The Last Traded Price is = " << document["lasttradeprice"].GetString() << std::endl;
}
/* always cleanup */
curl_easy_cleanup(curl);
}
//timer for URL request. *ADUJST ME AS DESIRED*
usleep(10000000);
}
return 0;
}
//Le Main
int main(void)
{
getData();
}
ios_base is in namespace std. Add prefix std:: before ios_base.

C++ query of JSON subObject error

my code compiles without error but at runtime I get the following error ->
testGetprice2.o: rapidjson/include/rapidjson/document.h:1125: rapidjson::SizeType rapidjson::GenericValue<Encoding, Allocator>::Size() const [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::SizeType = unsigned int]: Assertion `IsArray()' failed.
where it is failing is in my for () loop
std::cout << document[i]["lasttradeprice"].
I am trying to query for the subObject "lasttradeprice" but clearly accessing the object incorrectly.
How do I query the subobject correctly/get rid of this error?
code ->
#include "rapidjson/include/rapidjson/document.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <unordered_map>
#include <string>
using namespace rapidjson;
struct myData
{
std::fstream *file;
std::string *str;
};
size_t write_data(void *ptr, size_t size, size_t nmemb, myData *data)
{
size_t numBytes = size * nmemb;
if (data->file)
data->file->write((char*)ptr, numBytes);
if (data->str)
*data->str += std::string((char*)ptr, numBytes);
return numBytes;
}
//function to get coin data and perform analysis
int getData()
{
int count = 0;
//begin non terminating loop
while(true)
{
count++;
CURL *curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=155");
std::fstream file("/home/coinz/cryptsy/myfile.txt", std::ios_base::out | std::ios_base::ate);
std::string json;
myData data;
data.file = &file;
data.str = &json;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
/* Perform the request, res will get the return code */
CURLcode res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
{
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
else
{
file << std::endl;
//begin deserialization
Document document;
document.Parse(json.c_str());
for (SizeType i = 0; i < document.Size(); i++){
std::cout << document[i]["lasttradeprice"].GetString() << std::endl;
}
//assert(document.HasMember("return"));
//assert(document["return"].IsString());
//std::cout << "The Last Traded Price is = " << document["return"].GetString() << std::endl;
}
/* always cleanup */
curl_easy_cleanup(curl);
}
//timer for URL request. *ADUJST ME AS DESIRED*
usleep(10000000);
}
return 0;
}
//Le Main
int main(void)
{
getData();
}
gdb ->
(gdb) run
Starting program: /home/coinz/cryptsy/testGetprice2.o
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff5cc9700 (LWP 24708)]
[Thread 0x7ffff5cc9700 (LWP 24708) exited]
testGetprice2.o: rapidjson/include/rapidjson/document.h:1125: rapidjson::SizeType rapidjson::GenericValue<Encoding, Allocator>::Size() const [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::SizeType = unsigned int]: Assertion `IsArray()' failed.
Program received signal SIGABRT, Aborted.
0x00007ffff6fec795 in raise () from /lib64/libc.so.6
replace your loop with
std::cout << "The Last Traded Price is = " << document["return"]["markets"]["DRK"]["lasttrad
eprice"].GetString() << std::endl;
According to the original JSON the structure is the following:
{
"success":1,
"return":
{
"markets":
{
"DRK":
{
"marketid":"155",
"label":"DRK\/BTC",
"lasttradeprice":"0.00553336",
"volume":"14615.30200941",
"lasttradetime":"2014-10-25 14:35:09",
"primaryname":"DarkCoin",
"primarycode":"DRK",
"secondaryname":"BitCoin",
"secondarycode":"BTC",
"recenttrades":
You are tying to access
document[i]["lasttradeprice"]
but you should access
documents["return"]["markets"][i]["lasttradedprice"]

Segfault with multithreaded curl request

I'm having some trouble with a C++ program here. Basically I've written a simple wrapper for http requests, with the ability to do multiple requests at once.
Works absolutely fine, but when I do httpS requests, it crashes randomly in multithreaded mode. I'm using curl and posix threads.
Backtrace looks like this:
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80996)[0x7fea9046d996]
/lib/x86_64-linux-gnu/libc.so.6(+0x82b80)[0x7fea9046fb80]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0xf2)[0x7fea90470ae2]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(CRYPTO_realloc+0x49)[0x7fea8f9c6169]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(lh_insert+0x101)[0x7fea8fa4bfb1]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(+0xe844e)[0x7fea8fa4e44e]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(ERR_get_state+0xde)[0x7fea8fa4eeee]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(ERR_clear_error+0x15)[0x7fea8fa4f065]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x24e79)[0x7fea90f10e79]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x39ea0)[0x7fea90f25ea0]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0xf8fd)[0x7fea90efb8fd]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x219f5)[0x7fea90f0d9f5]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x35538)[0x7fea90f21538]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(curl_multi_perform+0x91)[0x7fea90f21d31]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(curl_easy_perform+0x107)[0x7fea90f19457]
./exbot[0x40273a]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7f6e)[0x7fea90cd6f6e]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7fea904e79cd]
Could this be a bug in libcrypto?
Can I somehow tell curl not to use libcrypto? Any alternatives?
It only crahes wenn using httpS requests and works fine with even 10000 simultaneous http queries.
Cheers,
Thomas
Just for completeness my code:
// simple wrapper for http requests
#ifndef _REQUEST_H_
#define _REQUEST_H_
#include <curl/curl.h>
#include <pthread.h>
#include <string>
#include <iostream>
//////////////////////////////////
// MACROS
//////////////////////////////////
#define ERR(_msg) std::cerr << __FUNCTION__ << ": " << _msg << std::endl
//////////////////////////////////
// REQUEST WRAPPER
//////////////////////////////////
typedef unsigned int uint;
class RequestWrapper
{
private: // non copyable
RequestWrapper();
RequestWrapper(const RequestWrapper &that);
RequestWrapper &operator=(const RequestWrapper &that);
public:
struct Response
{
Response() : msg(""), success(false) {}
std::string msg;
bool success;
};
static Response simpleGET(std::string url, uint timeout);
static size_t write(char *content, size_t size, size_t nmemb, void *userp);
};
//////////////////////////////////
// GET
//////////////////////////////////
inline size_t RequestWrapper::write(char *content, size_t size, size_t nmemb, void *userp)
{
std::string *buf = static_cast<std::string *>(userp);
size_t realsize = size * nmemb;
for (uint i = 0; i < realsize; ++i)
{
buf->push_back(content[i]);
}
return realsize;
}
inline RequestWrapper::Response RequestWrapper::simpleGET(std::string url, uint timeout)
{
Response resp;
CURL *curl;
CURLcode res;
std::string buf;
// send request
buf.clear();
curl = curl_easy_init();
if (!curl)
{
//ERR("libcurl init failed");
return resp;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void *>(&buf));
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
{
//ERR("libcurl request failed, CODE: " << res);
return resp;
}
curl_easy_cleanup(curl);
// done
resp.msg = buf;
resp.success = true;
return resp;
}
//////////////////////////////////
// MULTITHREADED REQUEST
//////////////////////////////////
class RequestList
{
private:
std::vector<std::string> _reqs;
static void *sender(void *payload);
static pthread_mutex_t _mutex;
public:
inline void add(std::string request)
{
_reqs.push_back(request);
}
inline void clear()
{
_reqs.clear();
}
std::vector<std::string> send(uint timeout) const;
struct Payload
{
std::string url;
std::vector<std::string> *out;
uint tout, index;
Payload(std::string url,
std::vector<std::string> *out,
uint tout, uint index) : url(url), out(out), tout(tout), index(index) { }
Payload() : url(""), out(NULL), tout(0), index(0) { }
};
};
//////////////////////////////////
// SEND MT REQUEST
//////////////////////////////////
pthread_mutex_t RequestList::_mutex;
void *RequestList::sender(void *payload)
{
Payload *pl = static_cast<Payload *>(payload);
RequestWrapper::Response resp = RequestWrapper::simpleGET(pl->url, pl->tout);
pthread_mutex_lock(&_mutex);
if (resp.success)
{
pl->out->at(pl->index) = resp.msg;
std::cerr << ".";
}
else
{
std::cerr << "x";
}
pthread_mutex_unlock(&_mutex);
return NULL;
}
inline std::vector<std::string> RequestList::send(uint timeout) const
{
std::vector<std::string> resp;
resp.resize(_reqs.size());
Payload *payloads = new Payload[_reqs.size()];
pthread_t *tids = new pthread_t[_reqs.size()];
// create mutex
pthread_mutex_init(&_mutex, NULL);
// prepare payload and create thread
for (uint i = 0; i < _reqs.size(); ++i)
{
payloads[i] = Payload(_reqs[i], &resp, timeout, i);
pthread_create(&tids[i], NULL, RequestList::sender, static_cast<void *>(&payloads[i]));
}
// wait for threads to finish
for (uint i = 0; i < _reqs.size(); ++i)
{
pthread_join(tids[i], NULL);
}
std::cerr << std::endl;
//destroy mutex
pthread_mutex_destroy(&_mutex);
delete[] payloads;
delete[] tids;
return resp;
}
#endif
Libcrypto is part of OpenSSL, which is not thread-safe unless you provide the necessary callbacks. According to the documentation, on a POSIX-compliant system (which has thread-local errno) the default thread-id implementation is acceptable, so you just need a locking function:
void locking_function(int mode, int n, const char *file, int line);
This function will need to maintain a set of CRYPTO_num_locks() mutexes, and lock or unlocks the n-th mutex depending on the value of mode. You can read the documentation for more details. The libcurl website actually has some sample code showing how to do this.
Alternatively, you can build libcurl with a different SSL library that is thread safe, such as GnuTLS.

CURL C API: callback was not called

The code below is a test for the CURL C API . The problem is that the callback function write_callback is never called. Why ?
/** compilation: g++ source.cpp -lcurl */
#include <assert.h>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <curl/curl.h>
using namespace std;
static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
std::cerr << "CALLBACK WAS CALLED" << endl;
exit(-1);
return size*nmemb;
}
static void test_curl()
{
int any_data=1;
CURLM* multi_handle=NULL;
CURL* handle_curl = ::curl_easy_init();
assert(handle_curl!=NULL);
::curl_easy_setopt(handle_curl, CURLOPT_URL, "http://en.wikipedia.org/wiki/Main_Page");
::curl_easy_setopt(handle_curl, CURLOPT_WRITEDATA, &any_data);
::curl_easy_setopt(handle_curl, CURLOPT_VERBOSE, 1);
::curl_easy_setopt(handle_curl, CURLOPT_WRITEFUNCTION, write_callback);
::curl_easy_setopt(handle_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
multi_handle = ::curl_multi_init();
assert(multi_handle!=NULL);
::curl_multi_add_handle(multi_handle, handle_curl);
int still_running=0;
/* lets start the fetch */
while(::curl_multi_perform(multi_handle, &still_running) ==
CURLM_CALL_MULTI_PERFORM );
std::cerr << "End of curl_multi_perform."<< endl;
//cleanup should go here
::exit(EXIT_SUCCESS);
}
int main(int argc,char** argv)
{
test_curl();
return 0;
}
Many thanks
Pierre
You need to check the value of still_running and call curl_multi_perform() again if there are still pending operations.
Simple example:
int still_running=0;
/* lets start the fetch */
do {
while(::curl_multi_perform(multi_handle, &still_running) ==
CURLM_CALL_MULTI_PERFORM);
} while (still_running);