I am getting this error deterministically and immediately every time I run the code below.
I am trying to use libcurl that I have built from source using nmap and using the recommended procedure and interestingly enough, I am able to send the same GET request using the built curl binary successfully. I am also able to send this query successfully using Postman.
This is the curl command that I am using (I am using <my.website>
in place of the actual host and <token>
in place of the actual correct token):
PS> cd C:curl-8.8.0buildslibcurl-vc-x86-release-static-ipv6-sspi-schannelbin
PS> ./curl --header "Authorization: Bearer <token>" https://<my.website>/api/test
… and I am getting back the expected:
Hello back
However, when I try the same in my C++ x86 project in Visual Studio 2022 like this:
#include <curl/curl.h>
#include <iostream>
void test(CURL* curl) {
// setup
const char* url = "https://<my.website>/api/test";
curl_easy_setopt(curl, CURLOPT_URL, url);
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Authorization: Bearer <token>");
setres = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// request
CURLcode res;
res = curl_easy_perform(curl);
std::cerr << "RESULT: " << res << std::endl;
// request result checking
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "POST request sent successfully!" << std::endl;
}
// cleanup
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
int main() {
// global initialization
CURL * curl;
curl_global_init(CURL_GLOBAL_SSL);
curl = curl_easy_init();
if (curl) {
test(curl);
} else {
std::cerr << "INIT FAILED" << std::endl;
}
// global cleanup
curl_global_cleanup();
}
… I get the following output:
* getaddrinfo() thread failed to start
* Could not resolve host: <my.website>
* Closing connection
RESULT: 6
curl_easy_perform() failed: Couldn't resolve host name
(the <my.website> is again just a placeholder; the real output contains the actual website, of course)
This problem appears immediately with basically zero waiting time (non-zero waiting times may indicate DNS problems acccording to some answers I found).
I have built libcurl "8.8.0 Schannel WinIDN" on my Windows 11 in a x86 mode (using Developer Command Prompt for VS 2022). This created the C:curl-8.8.0buildslibcurl-vc-x86-release-static-ipv6-sspi-schannel
with the include
, lib
and bin
subdirectories.
My project is constructed as a x86 project with the following options in properties:
C/C++ / General / Additional Include Directories: C:curl-8.8.0buildslibcurl-vc-x86-release-static-ipv6-sspi-schannelinclude
C/C++ / Preprocessor / Preprocessor Definitions: CURL_STATICLIB;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
Linker / General / Additional Library Directories: C:curl-8.8.0buildslibcurl-vc-x86-release-static-ipv6-sspi-schannellib
Linker / Input / Additional Dependencies: libcurl_a.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
While trying to figure out what’s wrong, I have read this post getaddrinfo thread failed to start #6495 which recommended to execute also the following:
curl_version_info_data* ver = curl_version_info(CURLVERSION_NOW);
std::cerr << "VERSION: " << curl_version() << std::endl;
if (!(ver->features & CURL_VERSION_ASYNCHDNS)) {
std::cerr << "SYNCHRONOUS" << std::endl;
} else if (!ver->age || ver->ares_num) {
std::cerr << "ARES" << std::endl;
} else {
std::cerr << "THREADED" << std::endl;
}
… which outputs:
VERSION: libcurl/8.8.0 Schannel WinIDN
THREADED
Which is what I would expect.
EDIT:
After painstakingly stepping through the libcurl calls, I have found that it ultimately fails on this code:
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listener == CURL_SOCKET_BAD)
return -1;
I cannot step into the socket
function to debug what’s happening there.
EDIT 2:
I figured that the socket()
method is actually a Windows method so I have created a separate project where I have only added this library:
Linker / Input / Additional Dependencies: Ws2_32.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)
… then even just the trivial code:
#include <iostream>
#include <winsock.h>
int main() {
// Create a socket (IPv4, TCP)
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
std::cerr << "Failed to create socket" << std::endl;
return 1;
}
std::cerr << "OK" << std::endl;
}
… results in:
Failed to create socket
Can someone please tell me what I am doing wrong?
2
Answers
The solution (also as @Botje suggested) was to do proper initialization at the start of the
main()
method:This solved it.
This line is the issue:
The
curl_global_init
function is responsible for initializing a number of subsystems. Normally you call it withCURL_GLOBAL_ALL
orCURL_GLOBAL_DEFAULT
, which include theCURL_GLOBAL_WIN32
flag.That flag initializes Winsock for you: