libcurl curl_easy_perform crash (Segmentation fault) c++ - c++

I am sorry for my bad English.
I am trying to run the following code but it crashes when the progress run about one day or several hours, so this crash is come up by accident.
By the way , The SecMonitor_Curl is a single Class, so curl_global_init() run only one time global.
I can not resolve this question, so I don't know what wrong with my program . Please help me. thanks!
SecMonitor_Curl::SecMonitor_Curl()
{
curl_global_init(CURL_GLOBAL_ALL);
}
SecMonitor_Curl::~SecMonitor_Curl()
{
curl_global_cleanup();
}
static size_t write_to_string(void *ptr, size_t size, size_t nmemb, void *stream) {
((std::string*)stream)->append((char*)ptr, 0, size*nmemb);
return size * nmemb;
}
int SecMonitor_Curl::http_get(const std::string url, const std::string method, const std::map<std::string, std::string>& params, std::string post_data, std::string& response)
{
int ret = 0;
CURLcode res;
curl_ = curl_easy_init();
if (curl_ == NULL)
{
return -1;
}
if(curl_)
{
url_t = "www.google.com";
method = "POST";
post_body="{"test":"test"}";
res = curl_easy_setopt(curl_, CURLOPT_URL, url_t.c_str());
if (method == "POST" || method == "PUT" || method == "DELETE")
{
curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, method.c_str());
curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, post_body.c_str());
curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, post_body.size());
}
res = curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L);
res = curl_easy_setopt(curl_, CURLOPT_NOSIGNAL, 1L);
res = curl_easy_setopt(curl_, CURLOPT_ACCEPT_ENCODING, "deflate");
std::string out;
res = curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, write_to_string);
res = curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &out);
//printf("curl_version : %s ",curl_version());
res = curl_easy_perform(curl_);
/* Check for errors */
if (res != CURLE_OK) {
srlog_error("SecMonitor_Curl | curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
ret = -1;
}
response = out;
}
else
{
ret = -1;
}
curl_easy_cleanup(curl_);
return ret;
}
This is the dump file :
Program terminated with signal 11, Segmentation fault.
#0 _IO_fwrite (buf=0x7f16a31dba70, size=2, count=1, fp=0x0) at iofwrite.c:43
43 iofwrite.c: No such file or directory.
in iofwrite.c
(gdb) bt
#0 _IO_fwrite (buf=0x7f16a31dba70, size=2, count=1, fp=0x0) at iofwrite.c:43
#1 0x00007f16a31aef93 in ?? () from /usr/lib64/libcurl.so.4
#2 0x00007f16a31af0c0 in Curl_debug () from /usr/lib64/libcurl.so.4
#3 0x00007f16a31afd69 in Curl_infof () from /usr/lib64/libcurl.so.4
#4 0x00007f16a31b55f4 in Curl_protocol_connect () from /usr/lib64/libcurl.so.4
#5 0x00007f16a31bbb0c in Curl_connect () from /usr/lib64/libcurl.so.4
#6 0x00007f16a31c3a90 in Curl_perform () from /usr/lib64/libcurl.so.4
#7 0x0000000000437a10 in SecMonitor_Curl::http_get (this=0x11e2db8, url=
"http://dip.alibaba-inc.com/api/v2/services/schema/mock/61919?spm=a312q.7764190.0.0.40e80cf75fUogt", method="POST", params=std::map with 5 elements = {...}, post_data="", response="")
at /home/albert.yb/secMonitorAgent/secMonitor/monitor/server/SecMonitor/SecMonitor_Curl.cpp:131
#8 0x0000000000435ab0 in SecMonitor_Cmd::run_cmd (this=0x11eeef8, cmd_name="update")
SecMonitor_Curl.cpp:131 : means curl_easy_perform().
Thanks

I collected 3 write_to_string callback function:
First :
static size_t write_to_string(void *ptr, size_t size, size_t nmemb, void *stream) {
((std::string*)stream)->append((const char*)ptr, size*nmemb);
return size * nmemb;
}
Second:
static size_t write_to_string(void *contents, size_t size, size_t nmemb, std::string *s)
{
size_t newLength = size*nmemb;
size_t oldLength = s->size();
try
{
s->resize(oldLength + newLength);
}
catch(std::bad_alloc &e)
{
//handle memory problem
return 0;
}
std::copy((char*)contents,(char*)contents+newLength,s->begin()+oldLength);
return size*nmemb;
}
Third:
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
write_to_string(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
These callback method can deal with this thing of output the curl response to String . But this problem is no in here, all crash because "crul_" which is the member variable of this class. when the function of "http_get" is quoting by multi thread , the crash must be happend.

Related

cURL write_callback does not pass userdata argument

I am trying to collect some data from a URL. If I do not define any CURLOPT_WRITEFUNCTION and CURLOPT_WRITEDATA I can obviously see the output on console. Then I tried to write that data to memory by copiying the example code, however userdata argument of my callback function returned NULL and I got following exception on line:
char* ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
Exception thrown: read access violation.
mem was nullptr.
Am I doing something wrong?
Here is my code:
struct MemoryStruct {
char* memory;
size_t size;
};
//-----------------
// Curl's callback
//-----------------
size_t CurlWrapper::curl_cb(char* data, size_t size, size_t nmemb, void* response)
{
size_t realsize = size * nmemb;
std::cout << "CALLBACK CALLED" << std::endl;
MemoryStruct* mem = (struct MemoryStruct*)response;
char* ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
if (!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), data, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
//--------------------
// Do the curl
//--------------------
void CurlWrapper::curl_api(
const std::string& url,
std::string& str_result)
{
MemoryStruct chunk;
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlWrapper::curl_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);
// TODO: enable ssh certificate
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // true
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // 2
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "zlib");
auto res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK) {
// nothing
std::cout << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
}
}
libcurl version: 7.82.0
Since libcurl is a C library, it does not know anything about C++ member functions or objects. You can overcome this "limitation" with relative ease using for example a static member function that is passed a pointer to the class.
See this example (from the everything curl book).
// f is the pointer to your object.
static size_t YourClass::func(void *buffer, size_t sz, size_t n, void *f)
{
// Call non-static member function.
static_cast<YourClass*>(f)->nonStaticFunction();
}
// This is how you pass pointer to the static function:
curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, YourClass::func);
curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, this);

c++ Libcurl ftp download/upload in memory

I am trying to download/(and later upload it again) a json file from a ftp server(provider: bplaced.net) into memory using LibCurl, but im getting an error.
Please don't be to harsh im pretty new to this. Also feel free to improve my code thanks :p
Memory methods:
struct MemoryStruct {
char* memory;
size_t size;
};
static size_t
WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct* mem = (struct MemoryStruct*)userp;
char* ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
if (ptr == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
Download Method:
std::string getFTPFileMem() {
CURL* curl;
CURLcode res;
std::string memory;
struct MemoryStruct chunk;
chunk.memory = (char*)malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL,
"ftp://user:pass#host/jsonLocation/Json.json");
/* send all data to this function */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);
/* We activate SSL and we require it for both control and data */
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
/* Switch on full protocol/debug output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
memory = chunk.memory;
/* always cleanup */
curl_easy_cleanup(curl);
if (CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return memory;
}
int main() {
std::cout << getFTPFileMem() << "\n";
}
FTP certificate issue:

C++ libcurl responses only show first line of response

EDIT: After running a few more commands, it seems that only lines starting with * are being shown. Any way to stop that?
I'm trying to use the libcurl library with my C++ program to recieve emails using the IMAP protocol. The issue is that the response from the CURL calls are only returning one line, and cutting off the rest of what is supposed to be returned. I know that the request itself is working because when I turn on verbose mode with curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);, it has the full result within the output.
For example, when I use curl_easy_setopt(curl, "FETCH 10000 (FLAGS BODY[HEADER.FIELDS (DATE FROM SUBJECT)])"); the response is:
* 10000 FETCH (FLAGS (\Seen) BODY[HEADER.FIELDS (DATE FROM SUBJECT)] {140}
When I turn on verbose mode, the console includes the full result:
< A003 OK [READ-WRITE] INBOX selected. (Success)
> A004 FETCH 10000 (FLAGS BODY[HEADER.FIELDS (DATE FROM SUBJECT)])
< * 10000 FETCH (FLAGS (\Seen) BODY[HEADER.FIELDS (DATE FROM SUBJECT)] {140}
< Date: Wed, 1 Apr 2020 01:59:45 -0500
< From: [REMOVED NAME] <[REMOVED EMAIL]>
< Subject: Testing subject here
<
< )
< A004 OK Success
I have tried multiple ways of outputting the data: to stdout, an external file, and in memory (then printed). I feel like the CURL result just isn't returning more than the first line for some reason. Here is the code if it helps (I'm using wxWidgets):
App.cpp - Ignore most of this, just calls the functions
#include "App.h"
#include "Frame.h"
#include "Config.h"
#include "IMAP.h"
wxIMPLEMENT_APP(App);
bool App::OnInit() {
curl_global_init(CURL_GLOBAL_SSL);
try {
Config config("settings.conf");
for(const auto& account : config["accounts"]) {
const char* url = account["incoming_server"].asCString();
const char* username = account["username"].asCString();
const char* password = account["password"].asCString();
IMAP connection(url, IMAP_DEFAULT_PORT);
if(connection.auth(username, password) == IMAP_SUCCESS) {
connection.select("INBOX");
auto folders = connection.getFolders();
}
}
} catch(std::exception& e) {
std::cerr << e.what() << std::endl;
exit(0);
}
curl_global_cleanup();
exit(1);
Frame *frame = new Frame("MailDuck", wxDefaultPosition, wxSize(100, 100));
frame->Show(true);
frame->Centre();
return true;
}
App.cpp
#include "IMAP.h"
IMAP::IMAP(const char *url, int port) {
this->url = url;
this->port = port;
}
IMAP_CODE IMAP::auth(const char *username, const char *password) {
this->username = username;
this->password = password;
if(execute().size == -1) return IMAP_FAILED;
else return IMAP_SUCCESS;
}
std::vector<Folder> IMAP::getFolders() {
std::vector<Folder> folders;
memory mem = execute("FETCH 10000 (FLAGS BODY[HEADER.FIELDS (DATE FROM SUBJECT)])");
std::cout << mem.response << std::endl;
free(mem.response);
return folders;
}
IMAP::memory IMAP::execute(const char *command) {
CURL *curl;
CURLcode res = CURLE_OK;
struct memory chunk { (char *) malloc(1), 0 };
curl = curl_easy_init();
std::string finalURL;
finalURL.append(this->url);
finalURL.append("/");
finalURL.append(this->mailbox);
if(curl) {
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_USERNAME, this->username);
curl_easy_setopt(curl, CURLOPT_PASSWORD, this->password);
curl_easy_setopt(curl, CURLOPT_URL, finalURL.c_str());
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, command);
res = curl_easy_perform(curl);
if(res != CURLE_OK) chunk.size = -1;
curl_easy_cleanup(curl);
} else chunk.size = -1;
if(chunk.size == -1) std::cerr << "ERROR >> Unable to call command: " << command << std::endl;
return chunk;
}
size_t IMAP::write_function(void *data, size_t size, size_t nmemb, void *userp) {
size_t real_size = size * nmemb;
auto *mem = (struct memory *) userp;
char *ptr = (char *) realloc(mem->response, mem->size + real_size + 1);
if(ptr == NULL) return 0;
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, real_size);
mem->size += real_size;
mem->response[mem->size] = 0;
return real_size;
}
void IMAP::select(const char *box) {
this->mailbox = box;
}
IMAP.h
#ifndef MAILDUCK_IMAP_H
#define MAILDUCK_IMAP_H
#include <map>
#include <vector>
#include <string>
#include <json/json.h>
#include <curl/curl.h>
#include <iostream>
#include <istream>
enum {
IMAP_DEFAULT_PORT = 993,
};
enum IMAP_CODE {
IMAP_SUCCESS = 1,
IMAP_FAILED = 0
};
class Folder : public std::vector<Folder> {
public:
std::string name;
};
class IMAP {
private:
const char *url, *username, *password, *mailbox = "";
int port;
struct memory { char *response; size_t size; };
memory execute(const char *command = nullptr);
static size_t write_function(void *data, size_t size, size_t nmemb, void *userp);
public:
IMAP(const char *url, int port);
IMAP_CODE auth(const char* username, const char* password);
std::vector<Folder> getFolders();
void select(const char *mailbox);
};
#endif
I've been stuck on this for a bit, so I appreciate any insight anyone could provide.
Figured it out! For all who get stuck like me:
Apparently the rest of the data is stuck in the header data, so add this:
struct memory chunk { (char *) malloc(1), 0 };
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&chunk);
And then my write function is exactly like the other one...
size_t IMAP::header_callback(char *data, size_t size, size_t nmemb, void *userp) {
size_t real_size = size * nmemb;
auto *mem = (struct memory *) userp;
char *ptr = (char *) realloc(mem->response, mem->size + real_size + 1);
if(ptr == NULL) return 0;
mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, real_size);
mem->size += real_size;
mem->response[mem->size] = 0;
return real_size;
}
Now I'm getting the full response.

How to pass a pointer to object method?

I'm trying to make a CurlResponse object encapsulating libcurl response. My implementation of curl options WRITEFUNCTION and HEADERFUNCTION is mostly the same, the only difference being that in first case I'm calling response->appendBody and in the second - response->appendHeader. I would like to have one function and pass a pointer to appropriate method as a parameter, e.g. WRITEDATA would be response->appendBody, and I could call writer(data). However when I execute the below code, I get an error:
error: cannot pass objects of non-trivially-copyable type ‘struct std::_Bind<std::_Mem_fn<void (CurlResponse::*)(std::basic_string<char>)>(CurlResponse*, std::_Placeholder<1>)>’ through ‘...’
...
#include <iostream>
#include <string>
#include <functional>
#include <curl/curl.h>
using namespace std;
class CurlResponse {
public:
void appendBody(string data) {
cout << "Append body " << data << endl;
}
void appendHeader(string data) {
cout << "Append header " << data << endl;
}
};
//size_t WriteMemoryCallback(char * contents, size_t size, size_t nmemb, CurlResponse* response)
size_t WriteMemoryCallback(char * contents, size_t size, size_t nmemb, function<void(string)> writer)
{
size_t realsize = size * nmemb;
string data(contents, realsize);
// response->appendBody(data);
writer(data);
return realsize;
}
size_t WriteHeaderCallback(char * contents, size_t size, size_t nmemb, CurlResponse* response)
{
size_t realsize = size * nmemb;
string data(contents, realsize);
response->appendHeader(data);
return realsize;
}
int main() {
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (! curl) return 1;
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost");
CurlResponse* response = new CurlResponse();
auto writeBody = std::bind(&CurlResponse::appendBody, response, placeholders::_1);
writeBody("Test writing to body");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, writeBody);
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteHeaderCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, response);
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
return 0;
}
How do I fix this? Does this mean I can use std::binded functions in the same function, but can't pass them anywhere?
The problem is that you are trying to pass a complex object through ..., as the compiler already tells you. The probably best solution is to first wrap the std::bind in a std::function object, to avoid having to repeat the complete type:
function<void(string)> writeBodyPass(writeBody);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeBodyPass);
You then have to fix the signature (and body) of your callback, as you are now receiving a pointer to the std::function object:
size_t WriteMemoryCallback(char * contents, size_t size, size_t nmemb, function<void(string)> *writer)
{
size_t realsize = size * nmemb;
string data(contents, realsize);
(*writer)(data);
return realsize;
}

Get page contents in C++

I've created a PHP and C# app that gets the users Xbox 360 Profile ID from their gamertag.
I was just wondering how I do a web request and put the page contents of the url into a string in C++.
Thanks.
Here's a down-and-dirty C++ HTTP fetcher I wrote using libCURL some time back.
It takes a URL and returns a string with the contents of a get request. Modify and flavor to taste:
/*
* HttpFetcher.h
*/
#ifndef _http_fetcher_
#define _http_fetcher_
#include <stdlib.h>
#include <string>
class HttpFetcher {
public:
std::string simpleGetRequest(std::string url);
private:
// Private methods to handle getting
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data);
};
#endif // ifndef _http_fetcher_
/*
* HttpFetcher.cpp
* Much of this is quite similar to examples on the libcURL site
*/
#include "HttpFetcher.h"
#include "curl.h"
#include "easy.h"
#include <iostream>
size_t HttpFetcher::WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
exit(EXIT_FAILURE);
}
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
std::string HttpFetcher::simpleGetRequest(std::string url)
{
std::string toReturn = "";
CURL *curl = NULL;
struct MemoryStruct chunk;
chunk.memory = (char*)malloc(1);
chunk.size = 0;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);
// Some requests fail without a user agent.
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
toReturn = std::string(chunk.memory);
}
free(chunk.memory);
return toReturn;
}