如果服务器重新启动,使用 libcurl 句柄(简单接口)从客户端到服务器的通信将失败。
该程序(粘贴在下面的代码)创建一个 curl 句柄,初始化 url、证书、超时、请求等选项。然后在每 2 秒的无限循环中使用 curl 句柄向服务器发送请求。
观察结果如下:
- 程序启动后,客户端到服务器的通信正确建立,消息交换没有任何错误。
- 后来我给服务器机器供电。当服务器关闭时,curl_easy_perform 失败,错误代码=28,“已达到超时(connect() 超时!)”。
- 然后我打开机器,在机器启动时,观察到 curl_easy_perform 失败,错误代码=7,“无法连接到服务器(无法连接到主机)”。
- 一旦 curl 句柄能够连接到服务器端口,观察到 ssl_read 错误,curl 错误代码 = 56,“从对等方接收数据时失败(SSL 读取:错误:14094412:SSL 例程:SSL3_READ_BYTES:sslv3 警报错误证书,errno 0) "
- 进一步向前 curl_easy_perform 失败,错误代码=58,“本地 SSL 证书有问题(无法使用客户端证书(未找到密钥或密码错误?))”,此后再也无法恢复。
- 如果我停止程序并重新启动,则连接建立成功。证书没有变化。
我无法找到为什么会curl_easy_perform
因 ssl_read 错误而失败以及为什么进一步说错误代码 = 58(无法使用客户端证书)。
由于最初使用相同的证书进行通信,并且在重新启动该过程之后,我认为证书没有问题。
我尝试了 openssl 命令来验证证书是否正确。
Linux# openssl x509 -noout -modulus -in /opt/certstore/VcCombined.pem | openssl md5
fe18e9f364d18eba9f39690563aca836
Linux# openssl rsa -noout -modulus -in /opt/certstore/default.key | openssl md5
fe18e9f364d18eba9f39690563aca836
Linux# openssl verify -CAfile /opt/certstore/sslca/CACertificate.pem /opt/certstore/VcCombined.pem
/opt/certstore/VcCombined.pem: OK
我不确定如何进一步调试此问题。如果它与 openssl 或 curl 或我的程序有关。
客户端:
curl --version
curl 7.25.0 (i686-pc-linux-gnu) libcurl/7.25.0 OpenSSL/0.9.8f zlib/1.2.1.2 libidn/0.5.6
Protocols: dict file gopher http https imap imaps pop3 pop3s rtsp smtp smtps telnet
Features: IDN IPv6 Largefile NTLM NTLM_WB SSL libz
服务器端:
curl --version
curl 7.25.0 (i686-pc-linux-gnu) libcurl/7.25.0 OpenSSL/1.0.0e zlib/1.2.1.2 libidn/0.5.6
Protocols: dict file gopher http https imap imaps pop3 pop3s rtsp smtp smtps telnet
Features: IDN IPv6 Largefile NTLM NTLM_WB SSL libz
程序:
using namespace std;
static std::string buffer;
static int writer(char *data, size_t size, size_t nmemb, std::string *buffer)
{
int result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
int main(void)
{
CURL *curl;
CURLcode res;
char request[4096];
char curl_errbuf[CURL_ERROR_SIZE];
int bytes_read = 0;
FILE *lFile = fopen("/tmp/getguid.xml", "r");
if (lFile == NULL)
{
printf("fopen Error: %s\n", strerror(res));
return 1;
}
memset(request, 0, 4096);
bytes_read = fread(request, sizeof(request), 1, lFile);
fclose(lFile);
curl = curl_easy_init();
struct curl_slist* lcurlHeaders = NULL;
lcurlHeaders = curl_slist_append(lcurlHeaders, "Content-Type: text/xml");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, lcurlHeaders);
curl_easy_setopt(curl, CURLOPT_URL, "https://10.65.124.221:443/xmlInternal/service-reg/forward");
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
char *lUCSInterfaceName = "eth0";
curl_easy_setopt(curl, CURLOPT_INTERFACE, lUCSInterfaceName);
curl_easy_setopt(curl, CURLOPT_SSLCERT, "/opt/certstore/VcCombined.pem");
curl_easy_setopt(curl, CURLOPT_SSLKEY, "/opt/certstore/default.key");
curl_easy_setopt(curl, CURLOPT_CAINFO, "/opt/certstore/sslca/CACertificate.pem");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char*)request);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(request));
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
while(1)
{
memset(curl_errbuf, 0, CURL_ERROR_SIZE);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
printf("curl_easy_perform Error: %s (%s)\n", curl_easy_strerror(res), curl_errbuf);
else
printf("curl_easy_perform succes\n");
sleep(2);
}
curl_slist_free_all(lCurlHeaders);
curl_easy_cleanup(curl);
return 0;
}