SSL 错误 OpenSSL SSL_write:从 c++98 libcrul 使用 curl 时出现 SSL_ERROR_ZERO_RETURN、errno 32

SSL error OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 32 when using curl from c++98 libcrul

提问人:Fooad Taha 提问时间:3/29/2023 最后编辑:273KFooad Taha 更新时间:3/29/2023 访问量:709

问:

我在一家公司工作,我们正在使用 libcurl 将数据从设备发送到云 大多数时候它都可以工作,但有时它只是抛出我在标题中的SSL错误,当错误发生时,它总是发送的第一条消息(数据是GZIP文件,由json文件+二进制/文档文件组成)

在日志中,它通常: 1.log . log用于发送,例如: CurlSender::Send:url:https://xxx-us-east-1.xxx.xxxxxx.com:443/v1/upload,数据: Xڼ»׎㜖¥W+?ö ö׌鯴sΔIх4sc÷n֮À6|ê륚sαAI÷<÷$c_ÁpIÙFYF÷÷ÿ ® ý¹¿[ÿퟷ [ɯdõ���û²鋱ÿþ矛ЌsɡϿþ ý{.ޫ湯²þ»l#ÿùûÿ3/4蟟û®ÿ^Gяsÿ&㖖뿂M蟲ÿq��ÿA®>Y«÷"Iÿg^§üù_ÿ坣]>ù5Ӹ¿®þߐ婒ƾaHRü㰸Gп

URL 中的 x 只是为了隐藏我的公司信息

然后在那之后,我得到这个日志: CurlSender::Send:发送结束并出现错误:OpenSSL SSL_write:SSL_ERROR_ZERO_RETURN,错误 32

该代码在运行名为 Gaia 的自定义 Linux 的 Linux 设备计算机上运行

我们正在使用 C++ 98(我知道很旧)

这是 CurlSender 函数代码的一部分,因为我无法共享所有内容:

static bool Send (  IN void* curl,
                    IN const std::map<std::string,std::string> & headersMap,
                    IN HttpClient::InitParams & initParams,
                    IN std::string& write_buffer,
                    IN char* err_buf,
                    IN std::string& unix_socket,
                    IN std::string& url,
                    IN const std::string& api_path,
                    IN const std::string& payload,
                    IN int timeout_secs,
                    IN bool is_multipart,
                    IN const std::string& file_path,
                    IN const std::string& target_file_path,
                    IN HttpClient::REQUEST_TYPE request_type,
                    IN bool use_fresh_connection,
                    OUT NAC::IS::SmartPtr<HttpClient::HttpResponse>& httpResponse )
{

    void* slist = NULL;
    
    void *post=NULL;
    void *last=NULL;
    // clear write buffer leftovers (if any)
    write_buffer.clear();
    std::string cookie_string;
...
switch (request_type)
    {
        case HttpClient::POST_REQUEST:
        {
            DM_SLOG( TD::All, "creating POST request");

                if (!file_path.empty())
                {
                    if (!payload.empty())
                    {
                        DM_SLOG(TE_IS, TD::Surprise, "uploading data from buffer and file is supported only when using multipart");
                        return false;
                    }

                    TE_EXT_FUNC(curl_easy_setopt_long)(curl, te_CURLOPT_POST, 1);
                    upload_file = true;
                }
                else
                {
                    TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_POSTFIELDS, payload.c_str());
                    TE_EXT_FUNC(curl_easy_setopt_long)(curl, te_CURLOPT_POSTFIELDSIZE, payload.size());
                }
            }
        }
        break;
TE_EXT_FUNC(curl_easy_setopt_write_callback)(curl, te_CURLOPT_WRITEFUNCTION, &HttpClient::WriteToMemoryFunc);
            TE_EXT_FUNC(curl_easy_setopt_ptr)(curl, te_CURLOPT_WRITEDATA, &write_buffer);

//set data
        TE_EXT_FUNC(curl_easy_setopt_ptr)(curl, te_CURLOPT_HTTPHEADER, slist);
        TE_EXT_FUNC(curl_easy_setopt_PROXYAUTH_BASIC_DIGEST_NTLM)(curl);

TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_ENCODING, ""); //tells the server that it can send the response compressed
        TE_EXT_FUNC(curl_easy_setopt_long)(curl, te_CURLOPT_NOSIGNAL, 1); //needed to run in a MT env otherwise process will crush :-( see: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
        TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_ERRORBUFFER, err_buf);
        TE_EXT_FUNC(curl_easy_setopt_write_callback)(curl, te_CURLOPT_HEADERFUNCTION,&HttpClient::HeaderFunc);
        TE_EXT_FUNC(curl_easy_setopt_ptr)(curl, te_CURLOPT_WRITEHEADER, &cookie_string);

httpResponse->m_url = full_url;

        //set connection timeout
        if (timeout_secs != -1)
        {
            TE_EXT_FUNC(curl_easy_setopt_long)(curl, te_CURLOPT_TIMEOUT, timeout_secs);
        }

        //client certs (if needed)
        if (!initParams.m_client_cert_params.m_client_cert_path.empty())
        {
            TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_SSLCERT, initParams.m_client_cert_params.m_client_cert_path.c_str());
            TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_SSLCERTTYPE, initParams.m_client_cert_params.m_client_cert_type.c_str());
            if (!initParams.m_client_cert_params.m_client_cert_private_key_path.empty())
            {
                TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_SSLKEY, initParams.m_client_cert_params.m_client_cert_private_key_path.c_str());
                TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_SSLKEYTYPE, initParams.m_client_cert_params.m_client_cert_private_key_type.c_str());             
            }
            if (!initParams.m_client_cert_params.m_client_cert_private_key_password.empty())
            {
                TE_EXT_FUNC(curl_easy_setopt_str)(curl, te_CURLOPT_KEYPASSWD, initParams.m_client_cert_params.m_client_cert_private_key_password.c_str());
            }
            
        }

        if(initParams.m_verbose_logs && !TE_EXT_FUNC(curl_easy_setopt_debug_callback)(curl, &HttpClient::s_CurlDebugCb))
        {
            DM_SLOG(TE_IS, TD::Surprise, "failed to set verbose looging");
        }

        if (use_fresh_connection)
        {
            TE_EXT_FUNC(curl_easy_setopt_long)(curl, te_CURLOPT_FRESH_CONNECT, 1L);
        }
        
        if (payload.size() < PAYLOAD_DEBUG_OUTPUT_SIZE)
        {
            DM_SLOG(TE_IS, TD::All, "<request> url: " << full_url << ", data:\n" << payload);
        }
        else
        {   
            std::string part_of_data =  payload.substr(0, PAYLOAD_DEBUG_OUTPUT_SIZE);
            DM_SLOG(TE_IS, TD::All, "<request> url: " << full_url << ", data:\n" << part_of_data);
        }

        httpResponse->m_is_send_success = true;
        
        bool res = TE_EXT_FUNC(curl_easy_perform )(curl);

        if (post != NULL) 
        {
            TE_EXT_FUNC(curl_formfree)(post);
        }
        if (!res)
        {
            DM_SLOG(TE_IS, TD::Surprise, "send ended with error: " << err_buf);
            httpResponse->m_send_error = err_buf;
            httpResponse->m_is_send_success = false;
            cleanup(curl, slist, fd_upload, fd_download);
            return false;
        }

“TE_EXT_FUNC”只是调用 curl 命令或任何其他 linux 命令的包装器

当函数调用:“bool res = TE_EXT_FUNC(curl_easy_perform )(curl);”,然后输入 if(!res) 条件时,会发生错误。

我尝试搜索此错误的解决方案或原因,但找不到任何具体内容,根据 OpenSSL 网站:

SSL_ERROR_ZERO_RETURN TLS/SSL 对等方已通过发送close_notify警报关闭了要写入的连接。无法读取更多数据。请注意,SSL_ERROR_ZERO_RETURN并不一定表示基础传输已关闭。

所以我的问题是:

  1. 如何解决/处理这个问题?
  2. 如何启用完整的 curl 日志记录并记录整个错误以及所有相关内容,以帮助找到此 + 未来错误的原因,而不是仅仅键入“SSL_ERROR_ZERO_RETURN,errno 32”,这没有帮助

我知道这太长了,但提前感谢任何回答的人

ssl libcurl c++98

评论


答:

0赞 Steffen Ullrich 3/29/2023 #1

另一端在发回响应之前已关闭连接。由于它只发生,因此有时对等方可能只是过载。如果您有权访问服务器,您可能会找出确切的原因,并可能增加服务器的资源。

在客户端上,您无法执行任何操作来防止这种情况发生。客户端上的唯一方法是重试请求,并希望下次成功。

评论

0赞 Fooad Taha 3/30/2023
发生这种情况时,我查看了服务器,但它的行为正常,没有高资源使用率(cpu,ram或IO)
0赞 Steffen Ullrich 3/30/2023
@FooadTaha:如果您可以访问服务器端,则需要调试问题的根本原因,因为服务器是突然关闭连接(或客户端和服务器之间的连接,例如防火墙)的人。高负载只是可能的原因之一,可能会有错误,对来自客户端的意外输入的反应......。但它符合我在回答中所说的:除了重试请求之外,您在客户端中无能为力。