how to build, install, and run curllib in c++ - c++

I'm trying to build, install, and run curllib in c++ on Windows 10 but locks up when the run starts. Here are steps:
Download curl-7.59.0.zip from https://curl.haxx.se/download.html
Extract to c:\opt\curl-7.59.0
Start Menu>Visual Studio 2015>Developer Command Prompt for VS2015
cd C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
vcvars64.bat
cd c:\opt\curl-7.59.0\winbuild
nmake /f Makefile.vc mode=dll MACHINE=x64 DEBUG=yes
In VS2015, Project>Properties>Configuration Properties>VC++ Directories>Include Directories, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\include\curl
In VS2015, Project>Properties>Configuration Properties>C/C++>General/Additional Include Directories, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\include\curl
In VS2015, Project>Properties>Configuration Properties>Linker>Additional Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
In VS2015, Project>Properties>Configuration Properties>Linker>General>Additional Library Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
In VS2015, Project>Properties>Configuration Properties>Linker>Input>Additional Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
Project>Properties>Platform shows Active(x64). Configuration: shows Active(Debug)
In VS2015, Project>Properties>Configuration Properties>C/C++>Preprocessor, add CURL_STATICLIB
In VS2015, Build>Clean Solution
In VS2015, Build>Rebuild Solution
The program runs but locks up. No error messages are written to the log file. In fact, it isn't even touched. If I comment out this line:
curl = curl_easy_init();
Then it will run. But of course then I don't have any access to curl which is the whole point.
Here is some code:
#include <curl.h>
vector<string> getDrawingNames(const string &projectName) {
logFile << "starting getDrawingNames" << endl;
vector<string> drwNames;
CURL *curl;
CURLcode res;
string readBuffer;
curl = curl_easy_init(); //DOESN'T LIKE THIS LINE
/*
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com");
//curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
logFile << readBuffer << endl;
}
*/
return drwNames;
}
Any suggestions?

Related

Getting "Problem with the SSL CA cert" error while using libcurl

I've built openssl 1.1.1 with --openssldir=< path to ssl >/ssl (link to /etc/ssl) and curl 7.76.1 with --with-ssl=< path to openssl >.
Compiled the following code:
#include <iostream>
#include <curl/curl.h>
int main()
{
CURL *curl = curl_easy_init();
if (curl)
{
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: */*");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, "https://<address>");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "<some data>");
curl_easy_perform(curl);
curl_slist_free_all(headers)
}
curl_easy_cleanup(curl);
}
When I'm running this code I get an error:
curl_easy_operation() failed : Problem with the SSL CA cert (path? access rights?)
I see in strace, that it's trying to open "/etc/pki/tls/certs/ca-bundle.crt"
But in my machines (Ubuntu 12 and Ubuntu 14) there is no folder "/etc/pki".
Why does curl use "/etc/pki" instead of "/etc/ssl"? How can I force it do use "/etc/ssl"?
I tried to build curl with --without-nss, but it didn't work.
EDIT:
My solution was adding this code:
ifstream caBundleFile("/etc/pki/tls/certs/ca-bundle.crt");
if (caBundleFile.good()) {
curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt");
caBundleFile.close();
} else {
curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/ssl/certs");
}
There are two popular formats of storing root certificates. First one is for RHEL/Centos like, and second is for Ubuntu like distros.

libcurl half as fast as curl

I am using libcurl to download files using the SFTP (protocol), it takes libcurl about twice as much times as it does using the curl executable.
This is the curl example I followed when designing this:
size_t my_fwrite(char* buffer, size_t size, size_t nmemb, File* file)
{
return size * nmemb; //Just return the size to prove that it's not the write
}
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
/** Setup URL/PORT/USERNAME/PASSWORD*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
CURLcode res = curl_easy_perform(curl);
if (CURLE_OK != res) {
// we failed
std::cout << "we failed due to '" << curl_easy_strerror(res) << "'\n";
}
// Close the file
curl_global_cleanup();
When running, I measured the time using chrono steady_clock, and it used about 39 seconds to download 119mb. Whereas using the curl command it took 16 seconds. I tried with lager files as well, and the same applied. When downloading 500mb libcurl used around 3 minutes, where curl would use 1,5 minutes. The curl binary and the API is compiled using CMake.
The curl command was:
curl -k sftp://username:password#host.com:port/path/to/file.zip --output file.zip
Do note that I used the compiled curl and not the system downloaded curl, as that one did not support sftp
EDIT:
It is compiled as release.
Running the very sleepy profiler on a debug compile executable gave me that most of the time was spent in Curl_multi_wait screeshot
CMAKE flags:
set(CMAKE_USE_LIBSSH2 ON)
set(CURL_ZLIB ON)
set(CMAKE_USE_OPENSSL ON)
set(BUILD_CURL_EXE ON)
set(CURL_STATICLIB ON)
EDIT2:
I compiled my code on both Ubuntu and Windows (GCC 10.1.0 and VS 2019 16.6.3), and both of them suffer from the same issue that using Libcurl is twice as slow than using the Curl binary I compile.

Getting cURL to work with Visual Studios 2017

*Edit: I got CURL working in VS 2017 on a 64 bit machine following these steps (see below for original problem):
First install vcpkg:
Clone vcpkg using gitbash into C:\Program Files
In a command prompt navigate to C:\Program Files\vcpkg
Run in the command prompt: .\bootstrap-vcpkg.bat
Run in the command prompt: vcpkg integrate install
Then use vcpkg and Visual Studios 2017 command prompt to install cURL:
Open a VS 2017 Command prompt and navigate to the vcpkg folder (where the vcpkg.exe is)
Run: vcpkg install curl[*]:x64-windows (note this can take around a half hour to download and run, don't worry if it looks like it is "stuck" at parts).
*Edit: previously my instructions said to run vcpkg install curl:x64-windows but I added on the [*] at the behest of #i7clock to enable sftp and scp protocols.
After this step, you should check to make sure that curl installed correctly. To do this you should create a new project in VS 2017 and try and include #include curl/curl.h without adding any additional include directories. If you cannot do this then something went wrong with your install of curl. You should remove curl (and perhaps even the vcpkg folder and do a clean install) until you can include curl/curl.h.
*Important Note: this will only work if you are using x64 debugger/compiling in x64! If you cannot include the curl directory check to make sure your debug is set to the correct version of Windows.
You may need to disable SSL peer verification as well:
Place the code curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); before the request (see below). Note this is only necessary because I could not figure how to get certificates to work with curl. I have an as-of-yet unanswered stackoverflow post regarding this problem here.
Here are some other steps you may need to try to get things running, but I ended up finding them not necessary:
Navigate to vcpkg\packages\curl_x64-windows\lib to find the libcurl.lib file.
Include the path to libcurl.lib in Additional Library Directories under Properties -> Linker
Included libcurl.lib in Additional Dependencies under Linker -> Input -> Additional Dependencies
Place CURL_STATICLIB in Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Here is my now working code:
#include "curl/curl.h"
void testCurl() {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
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);
}
curl_global_cleanup();
}
int main(){
testCurl();
return 0;
}
*Edit: Here is the rest of the explanation of my old problem before it was fixed:
I am trying to use cURL to make an API call so I can start getting real time stock data, but I am running into difficulties getting it to function in VS 2017. I have attempted an install using vcpckg using the following steps:
According to vcpkg documentation I should be able to now simply #include , but it can't find the folder. If I try including the "include" directory from vcpkg\packages\curl_x86\include and #include I can build my project. I can also access some of the classes, but if I try and set the curl_global_init(CURL_GLOBAL_DEFAULT) as in this example I get linker errors.
You've installed the x86 version of curl with vcpkg (That's the x86 in vcpkg\packages\curl_x86\include). You need to install the x64 version to match your project:
>vcpkg install curl:x64-windows
Here in 2021, on windows 10, using the current Visual Studio. vcpkg install curl[*]:x64-windows does not work. I get a BUILD_FAILED error. vcpkg install curl does work for me, and only takes ~30 seconds

c++ decrypt file downloaded from server

I'm new to this, so please bear with me..
I'm using the following function to download files from a web server.
This seems to work well without any major issues.
void downloadFile(const char* url, const char* fname) {
CURL *curl;
FILE *fp;
CURLcode res;
curl = curl_easy_init();
if (curl){
fp = fopen(fname, "wb");
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);
curl_easy_cleanup(curl);
fclose(fp);
}
}
downloadFile("http://servera.com/file.txt", "filename.txt");
Some of the files that are on the server have been encrypted (by me) using openssl using a command similar to:
openssl aes-256-cbc -a -salt -in secrets.txt -out secrets.txt.enc
These files download fine, but I'd like to have them download and be written to their locations decrypted all by the download function.
Is that possible ? If so can someone help me work out how.
The password to decrypt the files will be saved in an array along with several other entries.
Any ideas ?
Thanks
Of course that's possible. The openssl command line tool just uses the libssl library internally to do the crypto.
You can do the same; I won't give an introduction to libssl here. I trust you can find the openssl homepage and read the relevant man pages yourself :).

libcurl: curl_easy_perform fails with CURLE_SSL_CACERT_BADFILE after some time

I’m using libcurl 7.26.0 in my C++ application to communicate with server by https protocol. It works correctly but after ~20 minutes connection fails: curl_easy_perform returns CURLE_SSL_CACERT_BADFILE. I make curl_easy_cleanup of session then initialize it in the same way successfully but on curl_easy_perform it fails with the same error. Only restart of application helps.
I’ve checked that *.pem file is present on filesystem and access permissions of application were not changed during its run.
I’m using libcurl 7.26.0, Windows 7 x86, MSVC 2005.
Any help will be highly appreciated.
UPD: Problem reproduces only release mode.
if (curl)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
curl_easy_setopt(curl, CURLOPT_CAINFO, certificate_file_path);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curlErrorBuffer);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://ap....");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ss.str().c_str());
...
}
I tried the following:
curl-ca-bundle.crt
curl-ca-bundle-my-site.crt
curl-ca-bundle.pem
curl-ca-bundle-my-site.pem
ca-mysite.crt
ca-mysite.pem
but: CURLE_SSL_CACERT_BADFILE...
Path: /Users/user/Documents/Test test/CA/ca-any-version.pem/crt
I'm using cURL logging. It is turned on in this way:
curl_easy_setopt(m_curl_session, CURLOPT_DEBUGFUNCTION, curl_debug_trace)
At the beginning of the function curl_debug_trace log file is opened by fopen and at the end it is closed using fclose. In release mode for some reasons it does not close file and process runs to limit of opened files and cannot open cacert file.
The solution is to fopen log file once and leave it opened untill program runs.