I'm working on a program for personal use that scrapes a few webpages periodically. One of them requires the use of SSL, and its main URL actually is a load balancer that redirects to a different domain each time, out of a list of a handful (not sure if this is relevant). I'm quite new to libcurl and SSL in particular so I may be missing something obvious but I don't think so.
The program works fine for a while (so far, never longer than an hour) but once it gets the SSL connect error for the first time, it will keep giving the same error every time. It's always a different amount of time, and a different amount of successful requests, before it starts failing.
The error buffer always contains the following: schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
There's nothing useful in eventvwr
. Searches on that error code return results about issues with self signed certificates on earlier versions of Windows Server but little else. I don't control the server I'm connecting to, but I doubt it's a Windows box.
I've run out of ideas here, so I'm just going to give any details that may be relevant. I can't really post any actual source code because I've abstracted all the curl calls away in several classes so I would have to paste a lot of boilerplate code before others could make sense of it. I've confirmed with the Visual Studio debugger that this is what the actual calls boil down to, though.
I initialize libcurl in the main thread, before any others are created, like so: curl_global_init(CURL_GLOBAL_WIN32 | CURL_GLOBAL_SSL);
Then I create and initialize the actual curl handle in a second thread, and only in that thread, like so:
m_handle = curl_easy_init();
curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, write);
curl_easy_setopt(m_handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(m_handle, CURLOPT_DEBUGFUNCTION, debug);
curl_easy_setopt(m_handle, CURLOPT_VERBOSE, 1);
curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, &m_errormsg[0]);
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(m_handle, CURLOPT_COOKIEFILE, "");
I've experimented with setting both CURLOPT_SSL_VERIFYHOST
and CURLOPT_SSL_VERIFYPEER
to 0 but that didn't help.
I built libcurl from curl-7.43.0.tar.gz
with nmake /f Makefile.vc mode=static VC=12 ENABLE_WINSSL=yes ENABLE_SSPI=yes MACHINE=x64 DEBUG=yes
on Visual Studio 2013.
What's going on here and how can I fix it?
I'm going to guess that you're using a single CURL handle for all your requests (since you say "I create and initialize the actual curl handle"). The solution is most likely to create one CURL handle per each request done with curl_easy_perform(), and then curl_easy_cleanup() it immedately.
What you're seeing is probably caused by the server shutting down the SSL connection. But your CURL handle likely keeps its state as it is (i.e. with the handshake completed), which is no longer appropriate.
CURL *handle = curl_easy_init();
char url[] = "https://google.com";
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_perform(handle);
should work...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With