curl retry after transfer operation timeout - c

I have wrote a code that will download file with multiple curl handles in parallel from server in multipart and then it will merge the downloaded file parts. I am using curl_multi_perform and curl_multi_add_handle for this purpose. To give time out error after 60 seconds, if download operation get interuppted in between during download, i have used
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60L) and
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L) curl options. Now, i want to retry 5 times after every 60 seconds to retry download (or to connect again to server) after timeout occurs. How we can do that in C ?

Store the attempt counter in the private pointer CURLOPT_PRIVATE
void *private;
curl_easy_getinfo(curl, CURLINFO_PRIVATE, &private);
long counter = (long)(intptr_t)private;
counter++;
if (counter < 5) {
curl_easy_setopt(curl, CURLOPT_PRIVATE, (intptr_t)private);
curl_multi_add_handle(multi_handle, curl);
}

Related

Stop when using libcurl on tuxedo after check certification

I’m trying to use libcurl to call Rest API.
My server env : Oracle tuxedo(pro *c), AIX 7.1
It does work using command “curl” on prompt.
I can also see the whole log by using verbose option.
But it keeps stopping when I tried to use it on client compiling with libcurl.
According to log.
It says…
Trying 123.456.789.00:443…
Connected to “api url”(123.456.789.00) port 443 (#0)
ALPN, offering http/1.1
Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
successfully set certificate verify locations :
CAfile: /var/ssl/cert.pem
CApath: /var/ssl/certs/
And it stopped here!!!!
When I use curl command on prompt
It says exactly same,
But keeps going…
TLSv1.2 (OUT), TLS header, Certificate Status (22):
TLSv1.2 (OUT), TLS handshake, Client hello (1):
…
…
Etc…
I have no idea what causes this
And what is the difference…
Can anybody give me some advice please?
Or is there any other way to call RestAPI easily on Pro *C or C?
========================================
All I did is using sample of libcurl.
static sample(){
CURL *curl;
CURLcode res;
curl = curl_easy_init();
struct curl_slist *list = NULL;
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, "https://ApiUrl.here");
list = curl_slist_append(list, "Content-Type: application/json");
list = curl_slist_append(list, "ApiKey : realKey");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_SSLVERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
res = curl_easy_perform(curl);
curl_slist_free_all(list);
if(res != CURLE_OK){
fprintf(stderr, "curl_easy_perform() failed : %s \n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
}
list = curl_slist_append(list, "ApiKey : realKey");
I think that line is the issue.
RFC7230 3.2.4. Field Parsing
No whitespace is allowed between the header field-name and colon. In
the past, differences in the handling of such whitespace have led to
security vulnerabilities in request routing and response handling. A
server MUST reject any received request message that contains
whitespace between a header field-name and colon with a response code
of 400 (Bad Request). A proxy MUST remove any such whitespace from a
response message before forwarding the message downstream.
Remove the space:
list = curl_slist_append(list, "ApiKey: realKey");

cURL crashing in release mode, not in debug

I have used cURL in my app. It works fine (no errors) in debug mode. However, if i switch code to Release build, app start crashing. I am using VC 2013
My code:
data_downloads.curl = curl_easy_init();
data_downloads.curlData = (CURL_DOWNLOADED_DATA *)malloc(sizeof(CURL_DOWNLOADED_DATA));
data_downloads.curlData->data = (char *)malloc(sizeof(char));
data_downloads.curlData->data[0] = '\0';
curl_easy_setopt(data_downloads.curl, CURLOPT_WRITEFUNCTION, &my_curl_writeCallback);
curl_easy_setopt(data_downloads.curl, CURLOPT_WRITEDATA, data_downloads->curlData);
curl_easy_setopt(data_downloads.curl, CURLOPT_VERBOSE, 1L); //tell curl to output its progress
curl_easy_setopt(data_downloads.curl, CURLOPT_URL, USER_INFO_URL);
curl_easy_setopt(data_downloads.curl, CURLOPT_COOKIEFILE, "cookie.txt");
curl_easy_perform(data_downloads.curl); //-- it crashes here
I noticed that in debug mode, VC adds some space to the stack at every of your functions. Would a function briefly be out of bounds and overwrite a few bytes of the stack, then this will not be noticed...until you compile for release.
You should further check that all libraries for the release mode are the proper ones. VC knows many library types for many models (for DLLs, multi-threaded/not, ...). Check them against the libraries for your debugging mode.
These are the issues I came across. There may be other issues.

Libcurl with digest authorization in C: send http requests periodically

I'm developing a system that tracks objects with a P(an)T(ilt)Z(oom) camera which can be controlled via HTTP requests. The C application I develop is supposed to receive position data of the tracked object and to send commands to the camera to control the pan and tilt angle. In addition to these commands the camera has to receive a session refresh command every 5 seconds. HTTP Digest Authorization has to be used for the connection.
I'm sending the HTTP request with libcurl. I figured already out that for digest auth one needs to use on and the same curl handle for all requests in this stackoverflow post.
For sending the session refresh command periodically I tried to use a thread which is just doing this:
while(1)
{
usleep(5000000);
sessionContinue(g_Config.cam_ip);
}
With sessionContinue looking like this:
CURLcode sessionContinue(char* url)
{
CURLcode res;
char requestURL[40];
char referer[47];
struct curl_slist *headers=NULL;
strcpy(requestURL , url);
strcat(requestURL, CAM_SESSION_CONTINUE);
strcpy(referer , "Referer: http://");
strcat(referer , url);
strcat(referer , CAM_MONITOR);
headers = curl_slist_append(headers,"Connection:keep-alive");
headers = curl_slist_append(headers, camCookie);
// In windows, this will init the winsock stuff
curl_global_init(CURL_GLOBAL_ALL);
curl_easy_reset(curl);
if(curl)
{
// First set the URL that is about to receive our POST. This URL can
//just as well be a https:// URL if that is what should receive the
//data.
curl_easy_setopt( curl , CURLOPT_URL , requestURL );
curl_easy_setopt( curl , CURLOPT_HTTPHEADER , headers );
curl_easy_setopt( curl , CURLOPT_HTTPGET , 1 );
curl_easy_setopt( curl , CURLOPT_USERNAME , "root" );
curl_easy_setopt( curl , CURLOPT_PASSWORD , "password" );
curl_easy_setopt( curl , CURLOPT_HTTPAUTH , CURLAUTH_BASIC | CURLAUTH_DIGEST );
// 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:%d : %s\n", curl_easy_strerror(res) , __FILE__ , __LINE__ );
}
return res;
}
The application always crashed with segmentation fault after executing curl_easy_perform(curl). So I read the libcurl tutorial again and now I know that using one curl handle in multiple threads is a no go.
What I tried then was to use a timer with SIGALRM to implement the periodic session refresh. This didn't change the problem with the crash at curl_easy_perform(curl). The strange thing is that the application doesn't crash when sending the normal command to control the pan and tilt position which uses the same curl handle. The only difference between session refresh and pan/tilt command is that session refresh uses GET and pan/tilt uses POST.
Are there any other possibilities to send pan/tilt commands continuously with a short pause every 5 seconds used to send the session refresh?
You have a long range of problems in one small program. Here's a few:
You might overflow one of those small fixed-size buffers with the dangerous unbounded C functions you use. Quite likely one of them is the reason for the segfault.
curl_global_init() is documented to be called once, you call it over and over again - this even without calling curl_global_cleanup() in between. You obviously call curl_easy_init() somewhere out of the function and you should move the global init there.
'referer' gets filled with data but is never used otherwise
Another advice is to use CURLOPT_ERRORBUFFER to get error messages in rather than curl_easy_strerror() as you may get some extra details then. And of course to set CURLOPT_VERBOSE while debugging the request to see that things look the way you want it.
Thanks for your comment Daniel Stenberg. I'm now calling curl_global_init() just once when the handle has been set up. referer wasn't really needed here, but I had forgotten to remove it before pasting the code here.
The reason for the segmentation fault was that the session refresh command and the commands for pan and tilt tried to use one and the same curl handle at the same time, which obviously can't really work. So the solution with the timer and SIGALRM wasn't the problem. The segmentation faults have been solved by adding a mutex lock to avoid concurrent accesses to the curl handle.

libcurl clean CURLOPT_POSTFIELDS?

Hello what I am trying to do is send post method twice, however when I send it a second time the information from the first time is also being included and I do not want that.
To illustrate what I mean, this is the code that sends using post method. (the handle curl was already created)
void process(char* transferBuffer) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/cpp.php");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, transferBuffer);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
If I do something like:
process("name=John"); - webserver receives name=John
process("name=El"); - webserver receives name=John AND name=El
What I want to do is somehow clean previously used data;
the curl handle was already created ... What I want to do is somehow clean previously used data
All I can say is that if you want to reuse your curl handle - which is a best practice, you should reset it with curl_easy_reset before re-setting your options and re-performing the transfer.
Note that without the complete sample code (including the creation of your curl handle, etc) it is quite hard to provide a detailed answer.

MJPEG streaming with libcurl

I want to receive JPEG images from an IP-camera over HTTP. I am using LIBCURL for this purpose in my C program. The camera returns a single image with the following URL:
"http://143.205.116.14?image&res=full&x0=0&y0=0&x1=2944&y1=1920"
Using LIBCURL, I can receive a single image and write it to a .jpg file in the callback function. However, for continuous streaming, the camera accepts a GET request as follows:
"GET /mjpeg&res=full&x0=0&y0=0&x1=2944&y1=1920 HTTP/1.1\r\n HOST:143.205.16.14\r\n\r\n"
I was wondering how do I specify this GET request in libcurl. Is it possible to use in curl_easy_setopt()?
At present I use the following code to get a single image and save in the write_data callback function:
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()
{
curl = curl_easy_init();
if(curl) {
fp = fopen("C:\\trans.txt","wb");
curl_easy_setopt(curl, CURLOPT_URL, "http://143.205.116.14?image&res=full&x0=0&y0=0&x1=2944&y1=1920");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
How do I use the GET method so that the images are received continuously and saved by the callback function?
I'm not totally sure about this, but I think you must open the connection with CURL specify that the connection will be kept alive and then start downloading data.
With some type of while() you should download data and get each JPEG that the camera sent.
You must read about MJPEG codec, which has a structure where each JPEG is delimited by a header.
Have you tried using the full URL?
http://143.205.116.14/mjpeg&res=full&x0=0&y0=0&x1=2944&y1=1920
libcurl parses this and creates the GET request. GET is the default for HTTP, you have to add some code to get HEAD or POST (so you probably don't want to do that).

Resources