Goal:
To modify the libcurl example for HTTP/2 multiplexing that can be found here to save a payload response as it arrives into some buffer, instead of writing it to a file like the aforementioned example currently does. The payload within the buffer would then be available for things such as printing, searching for strings etc.
Expected output:
Program should print out each received payload response to stdout whenever the callback function detects that one has been delivered.
Actual output:
Sometimes the program works as expected for a small number of transfers (see line of code int num_transfers = 3 in main() further below). If the number of transfers is increased to say 8 or 10, sometimes the program doesn't function properly and the program will still print the output to stdout, but in the default format that libcurl will do if no CURL_WRITEFUNCTION/CURL_WRITEDATA has been included in the code, possibly suggesting nothing is being received by the callback function? Also in this scenario, an incorrect number of responses will be printed.
In the main do...while loop within main(), I set chunk.memory and chunk.size equal to 0 after they had been printed out. Without doing this, every time a new response was received these would continue growing. I'm unsure if this was the correct approach, however.
Current attempt:
Using the libcurl example that can be found here, I have attempted to mimic the functionality of writing the output to a callback function as seen below (instead of writing each response payload to a file).
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>
#ifndef CURLPIPE_MULTIPLEX
#define CURLPIPE_MULTIPLEX 0
#endif
struct CURLMsg *msg;
struct transfer {
CURL *easy;
unsigned int num;
FILE *out;
};
struct MemoryStruct {
char *memory;
size_t size;
};
struct MemoryStruct chunk;
#define NUM_HANDLES 1000
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) {
/* out of memory! */
std::cout << "not enough memory (realloc returned NULL)" << std::endl;
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
static void setup(struct transfer *t, int num)
{
CURL *hnd;
hnd = t->easy = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)&chunk);
/* set the same URL */
curl_easy_setopt(hnd, CURLOPT_URL, "https://someurl.xyz");
/* HTTP/2 please */
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
/* we use a self-signed test server, skip verification during debugging */
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
#if (CURLPIPE_MULTIPLEX > 0)
/* wait for pipe connection to confirm */
curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
#endif
}
int main() {
struct transfer trans[NUM_HANDLES];
CURLM *multi_handle;
int i;
int still_running = 0; /* keep number of running handles */
int num_transfers = 3;
chunk.memory = (char*)malloc(1);
chunk.size = 0;
/* init a multi stack */
multi_handle = curl_multi_init();
for(i = 0; i < num_transfers; i++) {
setup(&trans[i], i);
/* add the individual transfer */
curl_multi_add_handle(multi_handle, trans[i].easy);
}
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
// Main loop
do {
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
if(still_running) {
/* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
}
if(mc) {
break;
}
// Get response
do {
int queued;
msg = curl_multi_info_read(multi_handle, &queued);
if ((msg) && (msg->msg == CURLMSG_DONE) && (msg->data.result == CURLE_OK)) {
// Print the response payload
std::cout << "size: " << chunk.size << std::endl;
std::cout << chunk.memory << std::endl;
chunk.memory = 0;
chunk.size = 0;
}
} while (msg);
} while (still_running);
for(i = 0; i < num_transfers; i++) {
curl_multi_remove_handle(multi_handle, trans[i].easy);
curl_easy_cleanup(trans[i].easy);
}
free(chunk.memory);
curl_multi_cleanup(multi_handle);
return 0;
}
Summary question:
Q1. How can I modify the above program to correctly save a received payload response into a struct or a buffer asynchronously so that it can be available for functionality such as printing to stdout or searching for strings?
First, you should associate the transfer struct with a way of accessing the output:
struct transfer {
CURL *easy;
unsigned int num;
std::string contents;
};
and associate the CURLOPT_WRITEDATA with the pointer:
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)t);
Then, WriteMemoryCallback becomes:
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
transfer *t = (transfer *)userp;
size_t realsize = size * nmemb;
t->contents.append((const char *)contents, realsize);
return realsize;
}
Afterwards you can find the contents in the trans[i].contents variables.
Related
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:
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.
I have an application where I send base64 data of images from my OpenCV C++ code to an AWS URL which will find the age and gender of the faces in the images and send the results back in a JSON format.
I use cURL library to send the data through POST request. This part works fine, I am able to send the data and it the image is getting saved correctly every frame.
For reading the JSON data, I use the jsoncpp library to parse the JSON data.
I want to integrate both the parts in one function. This works as well when I send a single image. I have an issue when I send multiple images in a loop and receive their JSON responses. I keep receiving the first JSON response every time. I have tested this by generating random numbers and sending that as a JSON response each time on the server side and when I receive it in my C++ code, I only get the first JSON response, ie the first number, every time. But when I try receiving JSON data without sending POST data and just send a GET request, I receive the JSON data correctly every time. My code for both the parts integrated is here:
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
#include <stdio.h>
#include "opencv2/opencv.hpp"
#include "base64.h"
using namespace std;
using namespace cv;
/*Converts Mat to base64 string*/
string image_to_base64(Mat image)
{
string base64Output;
vector<uchar> vec_frame;
vector<int> vecCompression_params;
vecCompression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
vecCompression_params.push_back(90);
imencode(".jpg", image, vec_frame, vecCompression_params);
uchar *enc_msg = new uchar[vec_frame.size()];
for(int i=0; i < vec_frame.size(); i++)
enc_msg[i] = vec_frame[i];
base64Output = base64_encode(enc_msg, vec_frame.size());
std::replace(base64Output.begin(), base64Output.end(), '+', '-');
std::replace(base64Output.begin(), base64Output.end(), '/', '_');
std::replace(base64Output.begin(), base64Output.end(), '=', '*');
return base64Output;
}
/**Sends the base64 string to AWS**/
struct WriteThis
{
const char *readptr;
long long sizeleft;
};
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct WriteThis *pooh = (struct WriteThis *)userp;
if(size*nmemb < 1)
return 0;
if(pooh->sizeleft)
{
*(char *)ptr = pooh->readptr[0]; /* copy one single byte */
pooh->readptr++; /* advance pointer */
pooh->sizeleft--; /* less data left */
return 1; /* we return 1 byte at a time! */
}
return 0; /* no more data left to deliver */
}
string cURL_JSON_data;
size_t writeJSONURLCallback(char* buf, size_t size, size_t nmemb, void* up)//Callback function to store the URL's data
{
for (int c = 0; c<size*nmemb; c++)
{
cURL_JSON_data.push_back(buf[c]);
}
return size*nmemb;
}
string jsonTest;
tuple<string, string> send_base64(string base64_string)
{
CURL *curl;
CURLcode res;
long long int httpCode(0);
unique_ptr<std::string> httpData(new std::string());
string age_info, gender_info;
struct WriteThis pooh;
//cout<<"base64_string.length(): "<<base64_string.length();
char data[base64_string.length()];
strcpy(data, base64_string.c_str());
pooh.readptr = data;
pooh.sizeleft = (long long)strlen(data);
//cout<<"strlen(data): "<<strlen(data)<<endl;
/* In windows, this will init the winsock stuff */
res = curl_global_init(CURL_GLOBAL_DEFAULT);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_global_init() failed: %s\n",
curl_easy_strerror(res));
//return 1;
}
/* get a curl handle */
curl = curl_easy_init();
if(curl)
{
/* First set the URL that is about to receive our POST. */
curl_easy_setopt(curl, CURLOPT_URL, "MYURL");
/* Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* pointer to pass to our read function */
curl_easy_setopt(curl, CURLOPT_READDATA, &pooh);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeJSONURLCallback);//writes the conents of url
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //output cURL's progress
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
/* get verbose debug output please */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/*
If you use POST to a HTTP 1.1 server, you can send data without knowing
the size before starting the POST if you use chunked encoding. You
enable this by adding a header like "Transfer-Encoding: chunked" with
CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must
specify the size in the request.
*/
#ifdef USE_CHUNKED
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#else
/* Set the expected POST size. If you want to POST large amounts of data,
consider CURLOPT_POSTFIELDSIZE_LARGE */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (pooh.sizeleft));
#endif
#ifdef DISABLE_EXPECT
/*
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
header. You can disable this header with CURLOPT_HTTPHEADER as usual.
NOTE: if you want chunked transfer too, you need to combine these two
since you can only set one list of headers with CURLOPT_HTTPHEADER. */
/* A less good option would be to enforce HTTP 1.0, but that might also
have other implications. */
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Expect:");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#endif
/* 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_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
//cout<<"Testing_1"<<endl;
curl_easy_cleanup(curl);
}
curl_global_cleanup();
Json::Reader jsonReader;
Json::Value jsonData;
if (jsonReader.parse(cURL_JSON_data, jsonData))
{
cout << "Successfully parsed JSON data" << std::endl;
cout << "\nJSON data received:" << std::endl;
jsonTest = jsonData.toStyledString();
cout << jsonData.toStyledString() << std::endl;
age_info = jsonData["Age"].asString();
gender_info = jsonData["Gender"].asString();
}
else
{
cout<<"Could not parse JSON data"<<endl;
}
jsonData.clear();
return make_tuple(age_info, gender_info);
}
int main()
{
Mat frame;
string base64_data,age, gender;
int count = 0;
VideoCapture cap(1);
while(1)
{
cap>>frame;
count++;
resize(frame, frame, Size(frame.cols / 2, frame.rows / 2));
if(count % 10 ==0)//Sending the data every 10 frames
{
base64_data = image_to_base64(frame);
tie(age, gender) = send_base64(base64_data);
cout<<"age: "<<age<<", gender: "<<gender<<endl;
}
imshow("window", frame);
waitKey(30);
}
return 0;
}
And the code I use for receiving JSON with only GET request is here:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <memory>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
using namespace std;
string cURLdata;
size_t writeURLCallback(char* buf, size_t size, size_t nmemb, void* up)
{
for (int c = 0; c<size*nmemb; c++)
{
cURLdata.push_back(buf[c]);
}
return size*nmemb;
}
int main()
{
int count = 0;
while(1){
CURL* curl; //curl object
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "MYURL");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeURLCallback);//writes the conents of url
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //output cURL's progress
curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
Json::Reader jsonReader;
Json::Value jsonData;
bool parsedSuccess = jsonReader.parse(cURLdata,jsonData,false);
if (parsedSuccess)
{
std::cout << "Successfully parsed JSON data" << std::endl;
std::cout << "\nJSON data received:" << std::endl;
cout << jsonData.toStyledString() << std::endl;
}
else
{
std::cout << "Could not parse HTTP data as JSON" << std::endl;
}
jsonData.clear();
cURLdata.clear();
}
return 0;
}
Can someone help me point out what I'm doing wrong?
I have written program, that sends 5 emails through my gmail adress, with 1 minute pause between. This program works on my laptop, but not works on Raspberry Pi. On Raspberry Pi it sends only 1 email.
main.cpp:
#include <string>
#include <thread>
#include <chrono>
#include "email.c"
void threadFunction()
{
for (int i = 0; i < 5; i++)
{
std::string message = /*"Hello my name is Dmitry\r\nTest1\r\nTest2\r\n" + */std::to_string(i) + "\r\n";
int status = sent_email("*********", "*********", "Test message", message.c_str(), "smtps://smtp.gmail.com", "*********", "*********");
std::this_thread::sleep_for(std::chrono::minutes(1));
status++;
}
}
int main()
{
/*std::thread thr(threadFunction);
thr.join();*/
threadFunction();
return 0;
}
email.c:
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct upload_information {
const char *data;
size_t data_length;
size_t sent;
};
size_t read_callback(char *buffer, size_t size, size_t nitems, void *instream);
int sent_email(const char *FROM, const char *TO, const char *SUBJECT, const char *message, const char *server, const char *login, const char *password)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *recipients = NULL;
size_t length = strlen(message) + strlen(FROM) + strlen(TO) + strlen(SUBJECT) + 32; //32 is FROM: <>/n/r, TO: <>/n/r length and SUBJECT + new line(after header - SMTP standart) + /0
char *data;
data = (char*)malloc(sizeof(char) * length);
strcat(data, "FROM: <");
strcat(data, FROM);
strcat(data, ">\r\n");
strcat(data, "TO: <");
strcat(data, TO);
strcat(data, ">\r\n");
strcat(data, "SUBJECT: ");
strcat(data, SUBJECT);
strcat(data, "\r\n\r\n");
strcat(data, message);
struct upload_information upload_info;
upload_info.data = data;
upload_info.data_length = length;
upload_info.sent = 0;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_USERNAME, login);
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
curl_easy_setopt(curl, CURLOPT_URL, server);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
recipients = curl_slist_append(recipients, TO);
//recipients = curl_slist_append(recipients, CC);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_info);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
free(data);
return (int)res;
}
size_t read_callback(char *buffer, size_t size, size_t nitems, void *instream)
{
struct upload_information *upload_info = (struct upload_information *)instream;
if ((size == 0) || (nitems == 0) || (size * nitems < 1))
return 0;
if (upload_info->sent < upload_info->data_length)
{
size_t length = size * nitems;
if (length > upload_info->data_length - upload_info->sent)
length = upload_info->data_length - upload_info->sent;
memcpy(buffer, upload_info->data + upload_info->sent, length);
upload_info->sent += length;
return length;
}
return 0;
}
Error message on Raspberry Pi:
*** glibc detected *** ./Mailer: double free or corruption (!prev): 0x01d0da38 ***
P.S. Program on raspberry pi send 1 correct message and part of second message.
P.S.S Post was updated
The buffer you're allocating for the message is 1 byte to short. The total length of all the constant strings you're adding is 29, but you also need to add one more byte for the '\0' character that strcat will terminate the string with.
If you run the following code it shows you that concatenated length of all the string literals is 30:
#include <stdio.h>
int
main() {
printf("%d\n", (int) sizeof("FROM: <" ">\r\n"
"TO: <" ">\r\n"
"SUBJECT: " "\r\n"));
}
There are two other problem with the message. One is that you're not putting a blank line between the headers and the message as required. The other is that you're not terminating the final line of the message with \r\n. This might confuse the curl library as it will need to add the end of line terminator itself. If it doesn't the message won't be sent through SMTP correctly.
I have solved my problem. Problem was because of when i freeŠ² memory i am not reset memory.
I add *data = '\0'; befor strcat.
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;
}