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

1.1k Views Asked by At

i am working in a company and we are using libcurl in order to send data from appliance to cloud most of the time its working, but sometimes it just throws the SSL error i have in the title, when the error happens, its always the first message sent ( the data is gzip file consist of json file + binary/document file)

in the logs its usually: 1. log for sending, for example: CurlSender::Send: url: https://xxx-us-east-1.xxx.xxxxxx.com:443/v1/upload, data: xڼ»׎㜖¥w+?ö ö׌鯴sΔIх4sc÷n֮À6|ê륚sαAIÿþ뷯ÿüÿʺ¦ÿ£ɿõÿʊ蟲ÿq��ÿA®>Y«÷"Iÿg^§üù_ÿ坣]>ù5Ӹ¿®þߐ婒ƾaHRü㰸Gп摔$þ÷÷ʭ澸_ÁpIÙFYF$$c8ҤY"9d9F'dJb þ뿼/ÿZe/¶÷®ÿÿù¯<ù%ÿ£ùöÿ០X·÷¦þ ý¹¿[ÿퟷ�[ɯdõû²鋱ÿþ矛ЌſɡϿþý{.ޫ湯²þ»l#ÿùûÿ¾蟟û®ÿ^Gяsÿۿüÿ.»&㖖뿂M

the x's in the URL is just to hide my company information

then after that i get this log: CurlSender::Send: send ended with error: OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 32

the code is running on linux appliance machine running custom linux called Gaia

we are using C++ 98 (i know very old)

this is part of the code of the CurlSender function as i cannot share everything:

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" is just a wrapper to call the curl command or any other linux command

the error happens when the function calls: "bool res = TE_EXT_FUNC(curl_easy_perform )(curl);" and then enter the if(!res) condition.

i tried searching for solution or causes for this error, but couldnt find anything specific, per the openssl website:

SSL_ERROR_ZERO_RETURN The TLS/SSL peer has closed the connection for writing by sending the close_notify alert. No more data can be read. Note that SSL_ERROR_ZERO_RETURN does not necessarily indicate that the underlying transport has been closed.

so my questions is:

  1. how do solve/approach this issue?
  2. how do i enable full curl logging and log the whole error and everything related that can help find this + future errors cause in a better way than just typing " SSL_ERROR_ZERO_RETURN, errno 32" which isnt helpful

i know this is too long, but thanks in advance to whomever answers

1

There are 1 best solutions below

2
Steffen Ullrich On

The other side has closed the connection before sending the response back. Since it happens only sometimes the peer might just be overloaded. If you have access to the server you might figure out the exact cause and maybe increase resources of the server.

There is nothing on the client you can do to prevent this. The only way on the client is to retry the request and hope that it succeeds the next time.