diff --git a/docs/TODO b/docs/TODO index 79bd43006..8b133dc16 100644 --- a/docs/TODO +++ b/docs/TODO @@ -16,9 +16,8 @@ 1.3 struct lifreq 1.4 signal-based resolver timeouts 1.5 get rid of PATH_MAX - 1.6 progress callback without doubles - 1.7 Happy Eyeball dual stack connect - 1,8 Modified buffer size approach + 1.6 Happy Eyeball dual stack connect + 1.7 Modified buffer size approach 2. libcurl - multi interface 2.1 More non-blocking @@ -158,16 +157,7 @@ we need libssh2 to properly tell us when we pass in a too small buffer and its current API (as of libssh2 1.2.7) doesn't. -1.6 progress callback without doubles - - The progress callback was introduced way back in the days and the choice to - use doubles in the arguments was possibly good at the time. Today the doubles - only confuse users and make the amounts less precise. We should introduce - another progress callback option that take precedence over the old one and - have both co-exist for a forseeable time until we can remove the double-using - one. - -1.7 Happy Eyeball dual stack connect +1.6 Happy Eyeball dual stack connect In order to make alternative technologies not suffer when transitioning, like when introducing IPv6 as an alternative to IPv4 and there are more than one @@ -179,7 +169,7 @@ http://tools.ietf.org/html/rfc6555 -1.8 Modified buffer size approach +1.7 Modified buffer size approach Current libcurl allocates a fixed 16K size buffer for download and an additional 16K for upload. They are always unconditionally part of the easy diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c index 51a9c9b5e..b2635bc8a 100644 --- a/docs/examples/progressfunc.c +++ b/docs/examples/progressfunc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,9 +30,10 @@ struct myprogress { CURL *curl; }; -static int progress(void *p, - double dltotal, double dlnow, - double ultotal, double ulnow) +/* this is how the CURLOPT_XFERINFOFUNCTION callback works */ +static int xferinfo(void *p, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) { struct myprogress *myp = (struct myprogress *)p; CURL *curl = myp->curl; @@ -48,7 +49,9 @@ static int progress(void *p, fprintf(stderr, "TOTAL TIME: %f \r\n", curtime); } - fprintf(stderr, "UP: %g of %g DOWN: %g of %g\r\n", + fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T + " DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T + "\r\n", ulnow, ultotal, dlnow, dltotal); if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES) @@ -56,6 +59,19 @@ static int progress(void *p, return 0; } +/* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */ +static int older_progress(void *p, + double dltotal, double dlnow, + double ultotal, double ulnow) +{ + return xferinfo(p, + (curl_off_t)dltotal, + (curl_off_t)dlnow, + (curl_off_t)ultotal, + (curl_off_t)ulnow); +} + + int main(void) { CURL *curl; @@ -68,9 +84,28 @@ int main(void) prog.curl = curl; curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/"); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress); + + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress); /* pass the struct pointer into the progress function */ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog); + +#if LIBCURL_VERSION_NUM >= 0x072000 + /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will + compile as they won't have the symbols around. + + If built with a newer libcurl, but running with an older libcurl: + curl_easy_setopt() will fail in run-time trying to set the new + callback, making the older callback get used. + + New libcurls will prefer the new callback and instead use that one even + if both callbacks are set. */ + + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo); + /* pass the struct pointer into the xferinfo function, note that this is + an alias to CURLOPT_PROGRESSDATA */ + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog); +#endif + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); res = curl_easy_perform(curl); diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index e5ca09f4b..bebf8c08d 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -377,10 +377,54 @@ function that performs transfers. \fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually get called. +.IP CURLOPT_XFERINFOFUNCTION +Pass a pointer to a function that matches the following prototype: + +.nf +\fBint function(void *clientp, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow);\fP +.fi + +This function gets called by libcurl instead of its internal equivalent with a +frequent interval. While data is being transferred it will be called very +frequently, and during slow periods like when nothing is being transferred it +can slow down to about one call per second. + +\fIclientp\fP is the pointer set with \fICURLOPT_XFERINFODATA\fP, it is only +passed along from the application to the callback. + +The callback gets told how much data libcurl will transfer and has +transferred, in number of bytes. \fIdltotal\fP is the total number of bytes +libcurl expects to download in this transfer. \fIdlnow\fP is the number of +bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl +expects to upload in this transfer. \fIulnow\fP is the number of bytes +uploaded so far. + +Unknown/unused argument values passed to the callback will be set to zero +(like if you only download data, the upload size will remain 0). Many times +the callback will be called one or more times first, before it knows the data +sizes so a program must be made to handle that. + +Returning a non-zero value from this callback will cause libcurl to abort the +transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP. + +If you transfer data with the multi interface, this function will not be +called during periods of idleness unless you call the appropriate libcurl +function that performs transfers. + +\fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually +get called. + +(Added in 7.32.0) .IP CURLOPT_PROGRESSDATA Pass a pointer that will be untouched by libcurl and passed as the first argument in the progress callback set with \fICURLOPT_PROGRESSFUNCTION\fP. The default value of this parameter is unspecified. +.IP CURLOPT_XFERINFODATA +Pass a pointer that will be untouched by libcurl and passed as the first +argument in the progress callback set with \fICURLOPT_XFERINFOFUNCTION\fP. +The default value of this parameter is unspecified. This option is an alias +for CURLOPT_PROGRESSDATA. (Added in 7.32.0) .IP CURLOPT_HEADERFUNCTION Pass a pointer to a function that matches the following prototype: \fBsize_t function( void *ptr, size_t size, size_t nmemb, void diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 54b6dbc3d..e61cbbee9 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -428,7 +428,7 @@ CURLOPT_POSTREDIR 7.19.1 CURLOPT_PREQUOTE 7.9.5 CURLOPT_PRIVATE 7.10.3 CURLOPT_PROGRESSDATA 7.1 -CURLOPT_PROGRESSFUNCTION 7.1 +CURLOPT_PROGRESSFUNCTION 7.1 7.32.0 CURLOPT_PROTOCOLS 7.19.4 CURLOPT_PROXY 7.1 CURLOPT_PROXYAUTH 7.10.7 @@ -525,6 +525,8 @@ CURLOPT_WRITEDATA 7.9.7 CURLOPT_WRITEFUNCTION 7.1 CURLOPT_WRITEHEADER 7.1 CURLOPT_WRITEINFO 7.1 +CURLOPT_XFERINFODATA 7.32.0 +CURLOPT_XFERINFOFUNCTION 7.32.0 CURLPAUSE_ALL 7.18.0 CURLPAUSE_CONT 7.18.0 CURLPAUSE_RECV 7.18.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index e8ec9eee6..41c088108 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -156,12 +156,22 @@ struct curl_httppost { HTTPPOST_CALLBACK posts */ }; +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ typedef int (*curl_progress_callback)(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + #ifndef CURL_MAX_WRITE_SIZE /* Tests have proven that 20K is a very bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. @@ -968,13 +978,16 @@ typedef enum { /* 55 = OBSOLETE */ - /* Function that will be called instead of the internal progress display + /* DEPRECATED + * Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), - /* Data passed to the progress callback */ + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA /* We want the referrer field set automatically when following locations */ CINIT(AUTOREFERER, LONG, 58), @@ -1533,6 +1546,11 @@ typedef enum { /* Enable/disable SASL initial response */ CINIT(SASL_IR, LONG, 218), + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/progress.c b/lib/progress.c index 4cff2b76e..dac7f8d6e 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -357,12 +357,21 @@ int Curl_pgrsUpdate(struct connectdata *conn) } /* Calculations end */ if(!(data->progress.flags & PGRS_HIDE)) { - /* progress meter has not been shut off */ - if(data->set.fprogress) { - /* There's a callback set, so we call that instead of writing - anything ourselves. This really is the way to go. */ + if(data->set.fxferinfo) { + /* There's a callback set, call that */ + result= data->set.fxferinfo(data->set.progress_client, + data->progress.size_dl, + data->progress.downloaded, + data->progress.size_ul, + data->progress.uploaded); + if(result) + failf(data, "Callback aborted"); + return result; + } + else if(data->set.fprogress) { + /* The older deprecated callback is set, call that */ result= data->set.fprogress(data->set.progress_client, (double)data->progress.size_dl, (double)data->progress.downloaded, diff --git a/lib/url.c b/lib/url.c index c2bbfb30b..cda4e4825 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1609,8 +1609,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ + break; + + case CURLOPT_XFERINFOFUNCTION: + /* + * Transfer info callback function + */ + data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); + if(data->set.fxferinfo) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ break; + case CURLOPT_PROGRESSDATA: /* * Custom client data to pass to the progress callback diff --git a/lib/urldata.h b/lib/urldata.h index 47841e1f4..e245bfb4f 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1428,7 +1428,8 @@ struct UserDefined { curl_read_callback fread_func; /* function that reads the input */ int is_fread_set; /* boolean, has read callback been set to non-NULL? */ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */ - curl_progress_callback fprogress; /* function for progress information */ + curl_progress_callback fprogress; /* OLD and deprecated progress callback */ + curl_xferinfo_callback fxferinfo; /* progress callback */ curl_debug_callback fdebug; /* function that write informational data */ curl_ioctl_callback ioctl_func; /* function for I/O control */ curl_sockopt_callback fsockopt; /* function for setting socket options */