I am writing a c program using libcurl. I am connecting to a server running on localhost and then saving this retrieved data from server in a file. When I use the filename such as "file.txt", then I can write and read my file. But when I try to change the filename and append it with current data and time, I get an error "Failed Writing received data to disk/application".
Following is my code:
` int main(int argc, char *argv[])
{
float freq;
CURL *curl;
CURLcode res;
FILE *fp, *file_r;
char *buffer;
buffer = malloc (100000);
char url[1024], name[20];
char *filename;
filename = (char *) malloc (100);
if (filename == NULL)
{
printf("Error in memory allocation");
}`
/* Store the data retireved from webpage in a file and name the file with current date and time */
time_t now;
time (&now);
struct tm *t = localtime (&now);
strftime (name, 20, "%d %m %Y %H:%M:%S", t);
// printf ("%s\n", name);
filename[0] ='\0'; // Ensure the memory is an emtpy string;
strcat (filename, "file_new_");
strcat (filename, name);
strcat (filename, ".txt");
printf ("%s\n", filename);
printf("enter your input frequency value\n");
scanf("%f", &freq);
sprintf(url, "http://127.0.0.1:8080/?action=update_frequency&update_frequency=%f",freq);
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:8080");
/* Now specify the username & pwd */
curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:12345");
/* Specify the web request */
curl_easy_setopt(curl, CURLOPT_URL, url);
/* Storing the received data in a file */
fp = fopen (filename, "w+");
curl_easy_setopt (curl, CURLOPT_WRITEDATA, fp);
/* 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));
}
fclose (fp);
/* To read the return msg from server after performing a request */
file_r= fopen (filename, "r");
fseek (file_r, SEEK_SET, 0);
while (fgets (buffer, 100000, file_r)!=NULL)
{
;
}
printf( "%s\n", buffer);
fclose (file_r);
}
/* always cleanup */
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
}
If anyone has any idea, would be of great help.
Thanks much
You can't use the character : in a filename on Windows, so that's why it fails to save. Change the separator to something else.
Related
I am trying to test libcurl for my project, but when I want to download a test file I get error:
ERROR : Unknown error
but no reason why it happens,
my code:
#include <stdio.h>
#include <curl/curl.h>
int main(int argc, char **argv) {
CURL *curl;
FILE *fp;
char name[30] = {"Test"};
char link[100] = {"ipv4.download.thinkbroadband.com/5MB.zip"};
CURLcode error;
int result;
fp = fopen(name,"Wb");
curl = curl_easy_init();
curl_easy_setopt;(curl, CURLOPT_URL, argv[1] );
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_perform(curl);
result = curl_easy_perform(curl);
if (result = CURLE_OK)
printf("Sucessful download !");
else
printf("Could not download, ERROR : %s \n",curl_easy_strerror(error));
printf("%s",error);
fclose(fp);
curl_easy_cleanup(curl);
}
There's a bunch of errors in the code.
The argument to fopen should be a lower case "w".
You declare both error and result but should use only one.
There's a stray semicolon in the middle of this line: curl_easy_setopt;(curl, CURLOPT_URL, argv[1] );
Combined with what's already mentioned, this should work:
#include <stdio.h>
#include <curl/curl.h>
int main(int argc, char **argv) {
if(argc < 2) {
puts("URL not given");
return 1;
}
CURL *curl;
FILE *fp;
char name[30] = {"Test"};
char link[100] = {"ipv4.download.thinkbroadband.com/5MB.zip"};
CURLcode result;
fp = fopen(name,"w");
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, argv[1] );
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
result = curl_easy_perform(curl);
if (result == CURLE_OK)
printf("Sucessful download !");
else
printf("Could not download, ERROR : %s \n",curl_easy_strerror(result));
fclose(fp);
curl_easy_cleanup(curl);
return 0;
}
Don't forget to pass the URL as an argument, since you're not actually using link and don't check argc. And I advise you to learn how to use a debugger.
Complete guess - but could it have something to do with your code calling curl_easy_perform(curl); two times instead of once?
This looks suspicious:
curl_easy_perform(curl);
result = curl_easy_perform(curl);
Shouldn't it just be:
result = curl_easy_perform(curl);
Also, shouldn't link have the http prefix on it?
char link[100] = {"http://ipv4.download.thinkbroadband.com/5MB.zip"};
Regarding to your code indentation there are braces missing at least in your else path. That means that the last printf is being executed regardless of the result value...
Does it work as expected if you add the braces like this? Of course together with the other suggestions as stated by selbie and Emanuel P...
if (result == CURLE_OK) {
printf("Sucessful download !");
} else {
printf("Could not download, ERROR : %s \n",curl_easy_strerror(error));
printf("%s",error);
}
I am trying to write curl c code to using the http webdav put method to upload a file.
Using wireshark I have tried to capture the packets, there is 301 response from the server.
When I try to put the file from the PC to webserver it works fine
Below is the code:
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t retcode;
curl_off_t nread;
/* in real-world cases, this would probably get this data differently
as this fread() stuff is exactly what the library already would do
by default internally */
retcode = fread(ptr, size, nmemb, stream);
nread = (curl_off_t)retcode;
fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T
" bytes from file\n", nread);
return retcode;
}
int curlApache ()
{
CURL *curl;
CURLcode res;
FILE * hd_src;
struct stat file_info;
char *file;
char *url;
char error;
file = "/bd0/filecreate.txt";
url = "http://10.1.21.14/webdav/test.txt";
curl_slist *slist = NULL;
slist = curl_slist_append(slist, "Accept: text/xml");
slist = curl_slist_append(slist, "Depth: infinity");
slist = curl_slist_append(slist, "Connection: Keep-Alive");
slist = curl_slist_append(slist, "Content-Type: text/xml");
slist = curl_slist_append(slist, "Expect:");
/* get the file size of the local file */
stat(file, &file_info);
hd_src = fopen(file, "a+");
if (hd_src == NULL)
printf("Disc full or no permission\n");
const char *str = "This is the file content";
const char read[24];
if (hd_src != NULL)
if (fputs (str, hd_src) != EOF);
if( fgets (read, 24, hd_src)!=NULL )
{
/* writing content to stdout */
puts(read);
}
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 3L);
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* HTTP PUT please */
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
/* tell libcurl we can use "any" auth, which lets the lib pick one, but it also costs one extra round-trip and possibly sending of all the PUT data twice!!! */
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST);
curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:nimo0630");
fseek(hd_src, 0L, SEEK_END);
int file_size;
file_size = ftell(hd_src);
Curl_setopt(curl, CURLOPT_INFILE, hd_src);
Curl_setopt(curl, CURLOPT_INFILESIZE, file_size);
/* specify target URL, and note that this URL should include a file
name, not only a directory */
curl_easy_setopt(curl, CURLOPT_URL, url);
/* now specify which file to upload */
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
/* provide the size of the upload, we specicially typecast the value
to curl_off_t since we must be sure to use the correct data size */
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, curl_off_t)file_info.st_size);
/* Now run off and do what you've been told! */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
if(!res) {
/* extract the available authentication types */
long auth;
res = curl_easy_getinfo(curl, CURLINFO_HTTPAUTH_AVAIL, &auth);
if(!res)
{
if(!auth)
printf("No auth available, perhaps no 401?\n");
else
{
printf("%s%s%s%s\n", \
auth & CURLAUTH_BASIC ? "Basic ":"", \
auth & CURLAUTH_DIGEST ? "Digest ":"", \
auth & CURLAUTH_NEGOTIATE ? "Negotiate ":"", \
auth % CURLAUTH_NTLM ? "NTLM ":"");
}
}
}
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(hd_src); /* close the local file */
curl_global_cleanup();
return 0;
}
There is status code 301 returned from the server
I believe you want to understand how to debug this issue. If you paste your code, a more specific answer can be provided.
First check if you are able to upload file using command line curl. This will tell you if server is working fine
Check if the options you use are provided in C API
Check the API's are not returning any error
You could use tcpdump / wireshark to capture packets on the client or server to see if packets went out and what was the http content. You may not see any packet if API failed
I am writing a function in C and it'll work on Debian 8. What the function does is just downloading a file and scanning it by using cURL and ClamAV. So, there are two functions I wrote url2file() and clamav_scan(). And I want to insert url2file() into clamav_scan(). But, it'll show an error message 'Can't allocate memory'... why? If I delete a line url2file() in clamav_scan(), it works very well.
This below is my code I've written.
Thank you.
// this function scans a file by using ClamAV
int clamav_scan(const char* file_name)
{
int ret = 0;
struct cl_engine* engine = NULL; // clamAV engine
unsigned int signo = 0; // clamAV signature number
const char* path = NULL; // clamAV DB path
const char* virname = NULL; // virus name
unsigned long int scanned = 0; // size of scanned data
char target[MAX_PATH] = "./"; // path of the scan file
strcat(target, file_name);
if ((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
printf("cl_init() failed: %s\n", cl_strerror(ret));
exit(1);
}
if ((engine = cl_engine_new()) == NULL) {
printf("cl_engine_new() failed\n");
exit(1);
}
if ((path = cl_retdbdir()) == NULL) {
printf("cl_retdbdir() failed\n");
cl_engine_free(engine);
exit(1);
}
if ((ret = cl_load(path, engine, &signo, CL_DB_STDOPT)) != CL_SUCCESS) {
printf("cl_load() failed: %s\n", cl_strerror(ret));
cl_engine_free(engine);
exit(1);
}
if ((ret = cl_engine_compile(engine)) != CL_SUCCESS) {
printf("cl_engine_compile() failed: %s\n", cl_strerror(ret));
cl_engine_free(engine);
exit(1);
}
// this is the inserted function I said
// this function downloads a file by using cURL
url2file(url, file_name);
printf("Scanning %s ...\n", target);
if ((ret = cl_scanfile((const char*)target, &virname, &scanned, engine, CL_SCAN_STDOPT)) == CL_VIRUS) {
printf("Virus detected: %s\n", virname);
}
else {
printf("No virus detected\n");
if (ret != CL_CLEAN)
printf("Error: %s\n", cl_strerror(ret)); // shows message here
}
printf("scanned: %lu\n", scanned);
cl_engine_free(engine);
return EXIT_SUCCESS;
}
I referred to
https://curl.haxx.se/libcurl/c/url2file.html
https://raw.githubusercontent.com/vrtadmin/clamav-faq/master/manual/clamdoc.pdf
.
.
.
+++ added url2file() function
static size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream)
{
size_t written = fwrite(ptr, size, nmemb, (FILE*)stream);
return written;
}
int url2file(const char* url, const char* pagefilename)
{
CURL *curl_handle;
FILE *pagefile;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* set URL to get here */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
/* Switch on full protocol/debug output while testing */
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
/* disable progress meter, set to 0L to enable and disable debug output */
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
/* open the file */
pagefile = fopen(pagefilename, "wb");
if (pagefile) {
/* write the page body to this file handle */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
/* get it! */
curl_easy_perform(curl_handle);
/* close the header file */
fclose(pagefile);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return 0;
}
I have to trasfer files using FTP protocol and libcurl in c. It works fine, but I have some problems.
1) If a transfer is started, but at a certain point I disconnect from the network, my program remains in the libcurl function, the speed goes to 0 and I can't do anything else. I tried to set timeout (CURLOPT_TIMEOUT), but it's just a timeout on the transfer time.
2) The second problem I have, which is linked to the first one is, how can I know if the trasfer if successfully completed?
My trasfer code is:
struct FtpFile {
const char *filename;
FILE *stream;
};
long int size;
static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
struct FtpFile *out=(struct FtpFile *)stream;
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "ab");
if(!out->stream)
return -1; /* failure, can't open file to write */
}
return fwrite(buffer, size, nmemb, out->stream);
}
int sz;
int main(void)
{
CURL *curl;
CURLcode res;
char prova;
struct stat statbuf;
FILE *stream;
/* apro il file per leggere la dimensione*/
if ((stream = fopen("Pdf.pdf", "rb"))
== NULL)
{
fprintf(stderr, "Nessun file da aprire, il download partirĂ da zero.\n");
}
else
{
/* Ricevo informazioni sul file */
fstat(fileno(stream), &statbuf);
fclose(stream);
size = statbuf.st_size;
printf("Dimensione del file in byte: %ld\n", size);
}
struct FtpFile ftpfile={
"Pdf.pdf", /* name to store the file as if succesful */
NULL
};
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "ftp://....");
/* Define our callback to get called when there's data to be written */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* Set a pointer to our struct to pass to the callback */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
/* Switch on full protocol/debug output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/*Pass a long as parameter. It contains the offset in number of bytes that you want the transfer to start from.
Set this option to 0 to make the transfer start from the beginning (effectively disabling resume). For FTP, set
this option to -1 to make the transfer start from the end of the target file (useful to continue an interrupted
upload).
When doing uploads with FTP, the resume position is where in the local/source file libcurl should try to resume
the upload from and it will then append the source file to the remote target file. */
if(stream == NULL)
{
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0);
}
else
{
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, size);
}
/*Used to show file progress*/
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
if(CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
if(ftpfile.stream)
fclose(ftpfile.stream); /* close the local file */
curl_global_cleanup();
return 0;
}
I have recently answered a similar question to this.
1) this is by design. if you want to timeout the connection, try using these instead:
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time);
If your download rate falls below your desired threshold, you can check the connectivity & take whatever action you see fit.
NB: Added in 7.25.0: CURLOPT_TCP_KEEPALIVE, CURLOPT_TCP_KEEPIDLE
so these might be another suitable alternative for you.
2) like this:
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_bytes_remaining);
curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &dl_bytes_received);
if (dl_bytes_remaining == dl_bytes_received)
printf("our work here is done ;)\n");
I have a C program that opens a stream of tweets from Twitter API. What this program aims to do is to open a stream and write the stream to a text file. This program is successful when it just prints the stream in the terminal but when I change the code to write to a file there's now a "segmentation fault" error for about 40 seconds into the execution. size_t writefunc(void *ptr, size_t size, size_t nmemb, struct string *s) is the callback function that writes the stream to a file particularly at
fp=fopen("istream.txt", "a");
fprintf(fp, "%s", s->ptr);
fclose(fp);
Why is there a "segmentation fault" error? How should I fix this? I guess I am using the file pointer the wrong way.
==================================
#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 = 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;
size_t max_buffer = 10240;
FILE *fp;
fp=fopen("istream.txt", "a"); // <------------- the ERROR! Remove this.
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;
if( s->len >= max_buffer )
{
fp=fopen("istream.txt", "a");
fprintf(fp, "%s", s->ptr);
fclose(fp);
fflush( stdout );
free(s->ptr);
init_string( s );
}
return size*nmemb;
}
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
struct string s;
init_string(&s);
curl_easy_setopt(curl, CURLOPT_URL, "https://stream.twitter.com/1/statuses/sample.json");
//curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERPWD, "neilmarion:password");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
//printf("%s\n", s.ptr);
free(s.ptr);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
Most things looks correct in your program.
Most likely if fp=fopen("istream.txt", "a"); fails to open the file, it could be a segfault in the consecutive line.
Try to print the string in stderr instead to see. If that works, than issue is indeed in fp.
Other comment:
Since you are opening the file in append mode, there is actually no point in collecting the data in the buffer and keep re-allocating the buffer. You can at once append the file.
Every time you enter writefunc you open istream.txt:
FILE *fp;
fp=fopen("istream.txt", "a");
but you never call fclose on the fp. You do have this:
fp=fopen("istreaam.txt", "a");
fprintf(fp, "%s", s->ptr);
fclose(fp);
later on but the second fopen means that you no longer have a reference to the what the first fopen returned.
Eventually, you will run out of open files and further fopen calls will fail. Apparently this takes about 40 seconds. So get rid of the first fopen and try again.