cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: TFTP transfer is not aborted by non-zero value returnedbyCURLOPT_PROGRESSFUNCTION

From: Marcin Adamski <mass85_at_tlen.pl>
Date: Fri, 30 Sep 2011 14:29:19 +0200

Here is my quickly written code that will reproduce the problem. After transfer is started you have to somehow drop connection (i.e. shut network interface down which is used to transfer TFTP frames).

I apologise for not adapting it to cURL test suite. If I find time, I'll do it.

#include <iostream>
#include <cstring>
#include <cerrno>
#include <ctime>
#include "curl/curl.h"

char mErrorBuffer[CURL_ERROR_SIZE];

CURLM* multiHandle;
CURL* easyHandle;
    
bool CurlPerform()
{
    int still_running;
    CURLMcode result = curl_multi_perform(multiHandle, &still_running);

    if (result != CURLM_OK && result != CURLM_CALL_MULTI_PERFORM)
        std::cout << "CURL: curl_multi_perform returned error code: " << (int) result << " " << curl_multi_strerror(result) << std::endl;

    int msgsLeft;
    CURLMsg *msg;
    while ((msg = curl_multi_info_read(multiHandle, &msgsLeft)))
    {
        if (msg->msg == CURLMSG_DONE)
        {
            double param(-1);
            CURLcode easyResult = curl_easy_getinfo(easyHandle, CURLINFO_SPEED_DOWNLOAD, &param);
            if ( easyResult == CURLE_OK )
                std::cout << "CURL: Average download speed: " << param << " B/s" << std::endl;
            else
                std::cout << "CURL: could not get the average download speed, error: " << (int) easyResult << " " << curl_easy_strerror(easyResult) << std::endl;

            param = -1;
            easyResult = curl_easy_getinfo(easyHandle, CURLINFO_TOTAL_TIME, &param);
            if ( easyResult == CURLE_OK )
                std::cout << "CURL: download time: " << param << " s" << std::endl;
            else
                std::cout << "CURL: could not get the average download speed, error: " << (int) easyResult << " " << curl_easy_strerror(easyResult) << std::endl;
            
            result = curl_multi_remove_handle(multiHandle, msg->easy_handle);
            if (result != CURLM_OK)
                std::cout << "CURL: curl_multi_remove_handle returned error code: " << (int) result << " " << curl_multi_strerror(result) << std::endl;
            
            return true;
        }
    }
    
    return false;
}

int CurlProgressFunc(void* ptr, double TotalToDownload, double NowDownloaded, double TotalToUpload, double NowUploaded)
{
    static time_t lastRx = 0;
    static double lastDownloaded = 0;
    
    if (NowDownloaded && NowDownloaded > lastDownloaded)
    {
        lastDownloaded = NowDownloaded;
        lastRx = std::time(0);
    }
    
    if (lastRx && difftime(std::time(0), lastRx) > 5)
    {
        std::cout << "Returning 1 from callback!!!" << std::endl;
        return 1;
    }
    
    return 0;
}

int CurlDebugCallback (CURL *, curl_infotype infotype, char *buf, size_t size, void *)
{
    if (infotype == CURLINFO_TEXT)
    {
        char string[size+1];
        strncpy(string, buf, size);
        string[size] = '\0';
        
        std::cout << "CURL DEBUG: " << string << std::endl;
    }
    
    return 0;
}

int main(int argc, char** argv)
{
    if (argc != 3)
    {
        std::cout << "2 parameter are needed: url and local target path!!! " << argc << std::endl;
        return 1;
    }
    
    std::string url = argv[1];
    std::string localPath = argv[2];
    
    std::cout << "Starting cURL test for download of file" << std::endl;
    
    if (not (multiHandle = curl_multi_init()))
    {
        std::cout << "CURL: could not init easy interface!!!!!" << std::endl;
        return 1;
    }

    if (not (easyHandle = curl_easy_init()))
    {
        std::cout << "CURL: could not init easy interface!!!!!" << std::endl;
        return 1;
    }

    
    FILE* mFileHandle = fopen(localPath.c_str(), "w+");
                
    curl_easy_reset(easyHandle);

    mErrorBuffer[0] = '\0';
    curl_easy_setopt(easyHandle, CURLOPT_ERRORBUFFER, mErrorBuffer);
    
    curl_easy_setopt(easyHandle, CURLOPT_URL, url.c_str());
    
    curl_easy_setopt(easyHandle, CURLOPT_WRITEDATA, mFileHandle);

    curl_easy_setopt(easyHandle, CURLOPT_NOSIGNAL, 1l);

    curl_easy_setopt(easyHandle, CURLOPT_TIMEOUT, 5*3600l);
    curl_easy_setopt(easyHandle, CURLOPT_CONNECTTIMEOUT, 60l);
                

    curl_easy_setopt(easyHandle, CURLOPT_VERBOSE, 1l);
    curl_easy_setopt(easyHandle, CURLOPT_DEBUGFUNCTION, CurlDebugCallback);
        
    curl_easy_setopt(easyHandle, CURLOPT_NOPROGRESS, 0l);
    curl_easy_setopt(easyHandle, CURLOPT_PROGRESSFUNCTION, CurlProgressFunc);
                
    curl_easy_setopt(easyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
    
    CURLMcode result = curl_multi_add_handle(multiHandle, easyHandle);
    if (result != CURLM_OK)
    {
        std::cout << "CURL: could not curl_multi_add_handle!!!!!" << curl_multi_strerror(result) << std::endl;
        return 1;
    }
        
    
    while (true)
    {
        const int MAX_SELECT_TIMEOUT_SEC = 1;
        const int MAX_SELECT_TIMEOUT_USEC = 100000;
        
        struct timeval timeout = {MAX_SELECT_TIMEOUT_SEC, MAX_SELECT_TIMEOUT_USEC};
        
        fd_set fdRead;
        fd_set fdWrite;
        fd_set fdExcep;

        FD_ZERO(&fdRead);
        FD_ZERO(&fdWrite);
        FD_ZERO(&fdExcep);
        
        int curlMaxFd = -1;
        long curl_timeo = -1;
        

        if ( CURLM_OK != (result = curl_multi_fdset(multiHandle, &fdRead, &fdWrite, &fdExcep, &curlMaxFd)) )
            std::cout << "CURL: curl_multi_fdset failed with error code: " << (int) result << " " << curl_multi_strerror(result) << std::endl;
        else if ( CURLM_OK != (result = curl_multi_timeout(multiHandle, &curl_timeo)) )
            std::cout << "CURL: curl_multi_timeout failed with error code: " << (int) result << " " << curl_multi_strerror(result) << std::endl;
                
        if (curl_timeo >= 0)
        {
            if (timeout.tv_sec > (curl_timeo / 1000))
            {
                timeout.tv_sec = curl_timeo / 1000;
                timeout.tv_usec = (curl_timeo % 1000) * 1000;
            }
            else if (timeout.tv_sec == (curl_timeo / 1000))
            {
                timeout.tv_usec = (curl_timeo % 1000) * 1000;
            }
        }
        
        
        int status = select(curlMaxFd + 1, &fdRead, &fdWrite, &fdExcep, &timeout);
        
        if (status < 0)
        {
            std::cout << "Select escaped with: " << strerror(errno) << std::endl;
        }
        else if (status == 0)
        {
            timeout.tv_sec = MAX_SELECT_TIMEOUT_SEC;
            timeout.tv_usec = MAX_SELECT_TIMEOUT_USEC;
            
            if (CurlPerform())
                break;
        }
        else
        {
            if (CurlPerform())
                break;
        }
    }
    
    fclose(mFileHandle);
    
    return 0;
}

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2011-09-30