I am using two threads, one is downloading, other one is supposed to check how many bytes are downloaded.
Here is the exact code of my program:
#include <stdio.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
CURLcode res;
FILE *fp;
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
void *downloadThread() {
CURL *curl;
char *url = "http://imgsrc.hubblesite.org/hu/db/images/hs-2006-10-a-hires_jpg.jpg";
char outfilename[FILENAME_MAX] = "picture.jpg";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
printf("File download started\n");
res = curl_easy_perform(curl);
printf("File download finished\n");
curl_easy_cleanup(curl);
//fclose(fp);
}
}
void *checkThread() {
while(1) {
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int downloadedFile=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
//int downloadedFile = 0; /* instead of 0 it should be something with "res" variable */
printf("The file size is %d\n", downloadedFile);
usleep(1000000);
}
}
void setThread() {
//Thread settings
pthread_t tid1, tid2;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid1,&attr,downloadThread, NULL);
pthread_create(&tid2,&attr,checkThread, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
int main() {
setThread();
return 0;
}
So this one gives the result of what I wanted but I want to do this without saving into a file.
What about modify write_function like this?
time_t start_time = time(0);
size_t bytes_downloaded = 0;
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
time_t current_time = time(0);
time_t elapsed_time = current_time - start_time;
// do you still need it?
// size_t written;
// written = fwrite(ptr, size, nmemb, stream);
bytes_downloaded += (size * nmemb);
printf("Bytes downloaded %u in %u seconds at %u bytes/sec\n",
bytes_downloaded, elapsed_time, bytes_downloaded / elapsed_time);
return (size * nmemb);
}
Related
I am trying to send a POST type message with HTTPS communication using the curl.h library but I have some doubts:
It is necessary to have the certificate in a file (possibly inside the project folder) or it can be taken dynamically (as PostMan does for example).
How should the format of the sending of data be.
How to receive the data is equal to an HTTP?
This is my program:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <curl/curl.h>
BYTE str[20];
struct string
{
char *ptr;
size_t len;
};
void init_string(struct string *s)
{
s -> len = 0;
s -> ptr = malloc(s -> len + 1);
if (s -> ptr == NULL)
{
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}
s -> ptr[0] = '\0';
}
size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s)
{
size_t new_len = s -> len + size * nmemb;
s -> ptr = realloc(s -> ptr, new_len + 1);
if (s -> ptr == NULL)
{
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s -> ptr + s -> len, ptr, size * nmemb);
s -> ptr[new_len] = '\0';
s -> len = new_len;
return size * nmemb;
}
int post_function()
{
CURL *post;
CURLcode ret;
struct string s;
init_string(&s);
curl_global_init(CURL_GLOBAL_DEFAULT);
post = curl_easy_init();
curl_easy_setopt(post, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(post, CURLOPT_URL, "https://example.com/post.php");
curl_easy_setopt(post, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(post, CURLOPT_WRITEDATA, &s);
curl_easy_setopt(post, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(post, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(post, CURLOPT_POSTFIELDS, "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\nName\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
ret = curl_easy_perform(post);
if(ret == CURLE_OK)
{
sprintf(str, "Msj: %s\n", s.ptr);
}
else
{
//ERROR
}
curl_easy_cleanup(post);
curl_global_cleanup();
}
int main(int argc, char const *argv[])
{
post_function();
return 0;
}
After compiling my program i get this error:
I'm using Code::Blocks.Program is written to be easy download manager. Problem occurs with all types of files (pdf,txt,jpg). Here's my code. I don't know why is it happening. Please help.
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void)
{
CURL *curl;
FILE *fp;
CURLcode res;
int x;
char y[200];
char page;
char* outfilename;
char* path_pdf = "/home/user/Desktop/document.pdf";
char* path_jpg = "/home/user/Desktop/picture.jpg";
char* path_txt = "/home/user/Desktop/document.txt";
char FILEPATH[3] = {path_pdf, path_jpg, path_txt};
printf("Enter file url: \n"); // for example http://oi58.tinypic.com/15nk3de.jpg
scanf ("%s",y);
char *url = y;
printf("Choose type of file:\n [0] - pdf\n [1] - jpg\n [2] - txt\n "); //choose 1
scanf("%d",&x);
outfilename = FILEPATH[x];
curl = curl_easy_init();
if (curl)
{
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res == CURLE_OK)
{
printf("File downloaded!\n");
}
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
char FILEPATH[3] = {path_pdf, path_jpg, path_txt};
Is an array of char's (you want an array of strings), change to:
char *FILEPATH[3] = {path_pdf, path_jpg, path_txt};
I am trying to write a program in C to download some files.
The source code:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/easy.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(){
if(curl_global_init(CURL_GLOBAL_ALL)){
printf("curl error. Exiting.\n");
return 1;
}
char links[3][100] = {
"http://download.freeroms.com/nes_roms/08/big_nose_the_caveman.zip",
"http://download.freeroms.com/nes_roms/02/contra.zip",
"http://download.freeroms.com/nes_roms/08/super_mario_bros._(usajapan).zip"};
int n = 0, k = 0;
char *lastslash;
char* name;
CURL *handle = curl_easy_init();
CURLcode res;
FILE *file;
while(n<3){
lastslash = strrchr(links[n], '/');
name = lastslash ? lastslash + 1 : links[n];
printf("\nURL: %s\n", links[n]);
printf("Filename: %s\n", name);
curl_easy_setopt(handle, CURLOPT_URL, links[n]);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
file = fopen(name, "wb");
res = curl_easy_perform(handle);
fclose(file);
n++;
}
curl_easy_cleanup(handle);
return 0;
}
I can compile it, but this is the output when I run it :
URL: http://download.freeroms.com/nes_roms/08/big_nose_the_caveman.zip
Filename: big_nose_the_caveman.zip
Segmentation fault (core dumped)
My compiler setting:
gcc dl.c -lcurl -o dl
I found out that the problem occurs when it tries to execute curl_easy_perform(), but I don't know what to do with it.
try this coding.
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void) {
CURL *curl;
FILE *fp;
CURLcode res;
char *url = "http://localhost/aaa.txt";
char outfilename[FILENAME_MAX] = "C:\\bbb.txt";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/aaa.txt");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
You need to open the file before you set the callback data. The FILE* is stored by value, not reference.
file = fopen(name, "wb");
curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
I'm trying to get header contents of the webpage using libcurl and trying to store it in an charecter buffer .The program gives segmentation faults . I'm beginner to libcurl and i 'm not sure where the problem exists .Here's the code below .
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <curl/curl.h>
struct buf {
char *buffer;
size_t bufferlen;
size_t writepos;
} buffer = {0};
struct buf HeaderBuffer;
static size_t write_data(void *ptr, size_t size, size_t nmemb, char *string)
{
size_t nbytes = size*nmemb;
if (!HeaderBuffer.buffer) {
HeaderBuffer.buffer = malloc(1024);
HeaderBuffer.bufferlen = 1024;
HeaderBuffer.writepos = 0;
}
if (HeaderBuffer.writepos + nbytes < HeaderBuffer.bufferlen) {
HeaderBuffer.bufferlen = 2 * HeaderBuffer.bufferlen;
HeaderBuffer.buffer = (char *)realloc(HeaderBuffer.buffer, buffer.bufferlen);
}
assert(HeaderBuffer.buffer != NULL);
memcpy(HeaderBuffer.buffer+HeaderBuffer.writepos,ptr,nbytes);
return nbytes;
}
int main(void)
{
CURL *curl_handle;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://example.com");
/* send all data to this function */
curl_easy_setopt(curl_handle,CURLOPT_HEADERFUNCTION, write_data);
/* get it! */
curl_easy_perform(curl_handle);
printf("%s",HeaderBuffer.buffer);
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
return 0;
}
EDIT :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct string {
char *ptr;
size_t len;
};
void init_string(struct string *s) {
s->len = 0;
s->ptr = (char *)malloc(s->len+1);
if (s->ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(1);
}
s->ptr[0] = '\0';
}
size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s)
{
size_t new_len = s->len + size*nmemb;
s->ptr =(char *) realloc(s->ptr, new_len+1);
if (s->ptr == NULL) {
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s->ptr+s->len, ptr, size*nmemb);
//sprintf (s->ptr+s->len,"New header:\n%s\n",(char *)ptr);
s->ptr[new_len] = '\0';
s->len = new_len;
return size*nmemb;
}
int main(void)
{
CURL *curl;
CURLcode res;
char url[50];
char *ptr=NULL;
int i=0;
memset(Buffer,0,255);
strcpy(url,"http://");
strncat(url,"74.125.236.176",strlen("74.125.236.176"));
curl = curl_easy_init();
if(curl) {
struct string s;
init_string(&s);
curl_easy_setopt(curl, CURLOPT_URL,url);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, writefunc);
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &s);
res = curl_easy_perform(curl);
printf("\n \n %s",Buffer);
printf("%s\n", s.ptr);
free(s.ptr);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
Here I think you should do,
HeaderBuffer.bufferlen = nbytes * HeaderBuffer.bufferlen;
since you do not know nbytes,it may be greater than 2*HeaderBuffer.bufferlen.
I have homework where I need somehow to compare two HTTP responses. I am writing it on C and I use libcurl to make things easier. I am calling the function that uses libcurl to do a HTTP request and response from another function, and I want to return the HTTP response as a char *. Here is my code so far (it crashes):
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
char *handle_url(void) {
CURL *curl;
char *fp;
CURLcode res;
char *url = "http://www.yahoo.com";
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
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);
//printf("\n%s", fp);
}
return fp;
}
This solution C libcurl get output into a string works, but not in my case because I just want to return the string to the calling function.
Any ideas?
Fixed it for you. You need to handle the case where the write_data() function is called multiple times, and pass it the right kind of parameter. You also need to keep track of how big a structure you've got, so you can allocate enough memory.
I left in a debug printf in the write_data function to help you understand how it works.
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
struct url_data {
size_t size;
char* data;
};
size_t write_data(void *ptr, size_t size, size_t nmemb, struct url_data *data) {
size_t index = data->size;
size_t n = (size * nmemb);
char* tmp;
data->size += (size * nmemb);
#ifdef DEBUG
fprintf(stderr, "data at %p size=%ld nmemb=%ld\n", ptr, size, nmemb);
#endif
tmp = realloc(data->data, data->size + 1); /* +1 for '\0' */
if(tmp) {
data->data = tmp;
} else {
if(data->data) {
free(data->data);
}
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
memcpy((data->data + index), ptr, n);
data->data[data->size] = '\0';
return size * nmemb;
}
char *handle_url(char* url) {
CURL *curl;
struct url_data data;
data.size = 0;
data.data = malloc(4096); /* reasonable size initial buffer */
if(NULL == data.data) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
data.data[0] = '\0';
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
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 data.data;
}
int main(int argc, char* argv[]) {
char* data;
if(argc < 2) {
fprintf(stderr, "Must provide URL to fetch.\n");
return 1;
}
data = handle_url(argv[1]);
if(data) {
printf("%s\n", data);
free(data);
}
return 0;
}
Note: compile with gcc -o test test.c -lcurl (assuming you pasted into test.c). Use gcc -o test test.c -lcurl -DDEBUG to see the test printf() calls.
Disclaimer: this is ugly, quick-and-dirty code. There may be bugs. Please see the more robust, better commented example here.