sasha sasha - 4 months ago 16
C Question

How to access struct with CURLINFO_PRIVATE in libcurl?

I have been scratching my head about this for hours, I'm trying to access my struct from CURLINFO_PRIVATE, but gcc doesn't seem to recognize it as a struct:

10-at-a-time.c: In function 'main':
10-at-a-time.c:148:48: error: request for member 'size' in something not a structure or union
printf("%lu bytes retrieved\n", (long)chunk->size);
^
10-at-a-time.c:152:15: error: request for member 'memory' in something not a structure or union
free(chunk->memory);


In the libcurl documentation it says it will return a char pointer: https://curl.haxx.se/libcurl/c/CURLINFO_PRIVATE.html

As far as I have understood, I should be able to dereference that pointer with the "->" syntax and get the struct instance. But that doesn't seem to work.

Here is my code, I hope it's easy to understand:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <curl/multi.h>

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;

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;
}

static const char *urls[] = {
"http://www.microsoft.com",
"http://www.opensource.org",
"http://www.google.com",
"http://www.bbc.co.uk",
"http://www.newslink.org",
"http://www.un.org",
"http://www.news.com",
"http://www.cnn.com",
"http://www.wikipedia.org",
"http://www.dell.com",
"http://www.hp.com",
"http://www.cert.org",
"http://www.mit.edu",
"http://www.nist.gov",
"http://www.ebay.com",
"http://www.playstation.com",
"http://www.uefa.com",
"http://www.ieee.org",
"http://www.apple.com",
"http://www.symantec.com"
};

#define count sizeof(urls)/sizeof(char*)

static void init(CURLM *cm, int i)
{
CURL *eh = curl_easy_init();

struct MemoryStruct chunk;

chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */

curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(eh, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
curl_easy_setopt(eh, CURLOPT_URL, urls[i]);
curl_easy_setopt(eh, CURLOPT_PRIVATE, (void *)&chunk);
curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);
curl_multi_add_handle(cm, eh);
}

int main(void)
{
int bots = 10;

if (count < bots) {
bots = count;
}

CURLM *cm;
CURLMsg *msg;
long L;
struct timeval timeout;
unsigned int current = 0;

int msg_queue = -1;
int handles = -1;
int maxfd = -1;

fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;

curl_global_init(CURL_GLOBAL_ALL);
cm = curl_multi_init();

curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)bots);

for (current = 0; current < bots; ++current) {
init(cm, current);
}

while (handles) {
curl_multi_perform(cm, &handles);

if (handles) {
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);

if (curl_multi_fdset(cm, &fdread, &fdwrite, &fdexcep, &maxfd)) {
fprintf(stderr, "E: curl_multi_fdset\n");
return EXIT_FAILURE;
}

if (curl_multi_timeout(cm, &L)) {
fprintf(stderr, "E: curl_multi_timeout\n");
return EXIT_FAILURE;
}

if (L == -1) {
L = 100;
}

if (maxfd == -1) {
sleep((unsigned int)L / 1000);
}
else {
timeout.tv_sec = L / 1000;
timeout.tv_usec = (L % 1000) * 1000;

if (0 > select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout)) {
fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n", maxfd + 1, L, errno, strerror(errno));
return EXIT_FAILURE;
}
}
}

while ((msg = curl_multi_info_read(cm, &msg_queue))) {
if (msg->msg == CURLMSG_DONE) {
char *chunk;
CURL *e = msg->easy_handle;
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &chunk);
fprintf(stderr, "R: %d - %s\n", msg->data.result, curl_easy_strerror(msg->data.result));

printf("%lu bytes retrieved\n", (long)chunk->size);

curl_multi_remove_handle(cm, e);
curl_easy_cleanup(e);
free(chunk->memory);
}
else {
fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg);
}

if (current < count) {
init(cm, current++);
handles++;
}
}
}

curl_multi_cleanup(cm);
curl_global_cleanup();

return EXIT_SUCCESS;
}


I am new to C btw.

Answer

Set the private pointer:

ptr = [something];
curl_easy_setopt(curl, CURLOPT_PRIVATE, ptr);

Extract the pointer again from the handle it was set in:

curl_easy_getinfo(curl, CURLINFO_PRIVATE, &ptr);

In your case, when you extract the pointer again you need to make sure you have it as the correct struct pointer and not just a char *. Like perhaps:

struct MemoryStruct *chunk;
curl_easy_getinfo(curl, CURLINFO_PRIVATE, &chunk);

... as then you can access the struct and its fields.