... | ... |
@@ -63,6 +63,7 @@ |
63 | 63 |
#include <dirent.h> |
64 | 64 |
#include <errno.h> |
65 | 65 |
#include <zlib.h> |
66 |
+#include <math.h> |
|
66 | 67 |
|
67 | 68 |
#ifdef _WIN32 |
68 | 69 |
#include <wincrypt.h> |
... | ... |
@@ -226,6 +227,125 @@ done: |
226 | 226 |
} |
227 | 227 |
#endif |
228 | 228 |
|
229 |
+#if LIBCURL_VERSION_NUM >= 0x073d00 |
|
230 |
+/* In libcurl 7.61.0, support was added for extracting the time in plain |
|
231 |
+ microseconds. Older libcurl versions are stuck in using 'double' for this |
|
232 |
+ information so we complicate this example a bit by supporting either |
|
233 |
+ approach. */ |
|
234 |
+#define TIME_IN_US 1 |
|
235 |
+#define TIMETYPE curl_off_t |
|
236 |
+#define TIMEOPT CURLINFO_TOTAL_TIME_T |
|
237 |
+#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3000000 |
|
238 |
+#else |
|
239 |
+#define TIMETYPE double |
|
240 |
+#define TIMEOPT CURLINFO_TOTAL_TIME |
|
241 |
+#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3 |
|
242 |
+#endif |
|
243 |
+ |
|
244 |
+#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 6000 |
|
245 |
+ |
|
246 |
+struct xfer_progress { |
|
247 |
+ TIMETYPE lastRunTime; /* type depends on version, see above */ |
|
248 |
+ uint8_t bComplete; |
|
249 |
+ CURL *curl; |
|
250 |
+}; |
|
251 |
+ |
|
252 |
+/** |
|
253 |
+ * Function from curl example code, Copyright (C) 1998 - 2018, Daniel Stenberg, see COPYING.curl for license details |
|
254 |
+ * Progress bar callback function ( CURLOPT_XFERINFOFUNCTION ). |
|
255 |
+ */ |
|
256 |
+static int xferinfo(void *prog, |
|
257 |
+ curl_off_t TotalToDownload, curl_off_t NowDownloaded, |
|
258 |
+ curl_off_t TotalToUpload, curl_off_t NowUploaded) |
|
259 |
+{ |
|
260 |
+ struct xfer_progress *xferProg = (struct xfer_progress *)prog; |
|
261 |
+ CURL *curl = xferProg->curl; |
|
262 |
+ TIMETYPE curtime = 0; |
|
263 |
+ TIMETYPE remtime = 0; |
|
264 |
+ |
|
265 |
+ uint32_t i = 0; |
|
266 |
+ uint32_t totalNumDots = 40; |
|
267 |
+ uint32_t numDots = 0; |
|
268 |
+ double fractiondownloaded = 0.0; |
|
269 |
+ |
|
270 |
+ if ((TotalToDownload <= 0.0) || (xferProg->bComplete)) { |
|
271 |
+ return 0; |
|
272 |
+ } |
|
273 |
+ |
|
274 |
+ fractiondownloaded = (double)NowDownloaded / (double)TotalToDownload; |
|
275 |
+ numDots = round(fractiondownloaded * totalNumDots); |
|
276 |
+ |
|
277 |
+ curl_easy_getinfo(curl, TIMEOPT, &curtime); |
|
278 |
+ |
|
279 |
+ xferProg->lastRunTime = curtime; |
|
280 |
+ remtime = (curtime * 1 / fractiondownloaded) - curtime; |
|
281 |
+ |
|
282 |
+#ifdef TIME_IN_US |
|
283 |
+ if (fractiondownloaded <= 0.0) { |
|
284 |
+ fprintf(stdout, "Elapsed: %" CURL_FORMAT_CURL_OFF_T ".%06ld sec. ", |
|
285 |
+ (curtime / 1000000), (long)(curtime % 1000000)); |
|
286 |
+ } else { |
|
287 |
+ fprintf(stdout, "Elapsed: %" CURL_FORMAT_CURL_OFF_T ".%06ld sec, Remaining; %f sec. ", |
|
288 |
+ (curtime / 1000000), (long)(curtime % 1000000), |
|
289 |
+ (remtime / 1000000), (long)(remtime % 1000000)); |
|
290 |
+ } |
|
291 |
+#else |
|
292 |
+ if (fractiondownloaded <= 0.0) { |
|
293 |
+ fprintf(stdout, "Elapsed: %f sec. ", curtime); |
|
294 |
+ } else { |
|
295 |
+ fprintf(stdout, "Elapsed: %f sec, Remaining: %f sec. ", curtime, remtime); |
|
296 |
+ } |
|
297 |
+#endif |
|
298 |
+ |
|
299 |
+ if (TotalToUpload > 0.0) { |
|
300 |
+ fprintf(stdout, "Uploaded: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T, |
|
301 |
+ NowUploaded, TotalToUpload); |
|
302 |
+ } else if (TotalToDownload > 0.0) { |
|
303 |
+ fprintf(stdout, "Downloaded: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T, |
|
304 |
+ NowDownloaded, TotalToDownload); |
|
305 |
+ } |
|
306 |
+ |
|
307 |
+ fprintf(stdout, " ["); |
|
308 |
+ if (numDots > 0) { |
|
309 |
+ if (numDots > 1) { |
|
310 |
+ for (i = 0; i < numDots - 1; i++) { |
|
311 |
+ fprintf(stdout, "="); |
|
312 |
+ } |
|
313 |
+ fprintf(stdout, ">"); |
|
314 |
+ i++; |
|
315 |
+ } |
|
316 |
+ } |
|
317 |
+ for (; i < totalNumDots; i++) { |
|
318 |
+ printf(" "); |
|
319 |
+ } |
|
320 |
+ if (NowDownloaded < TotalToDownload) { |
|
321 |
+ fprintf(stdout, "] \r"); |
|
322 |
+ } else { |
|
323 |
+ fprintf(stdout, "] \n"); |
|
324 |
+ xferProg->bComplete = 1; |
|
325 |
+ } |
|
326 |
+ fflush(stdout); |
|
327 |
+ |
|
328 |
+ return 0; |
|
329 |
+} |
|
330 |
+ |
|
331 |
+#if LIBCURL_VERSION_NUM < 0x072000 |
|
332 |
+/** |
|
333 |
+ * Function from curl example code, Copyright (C) 1998 - 2018, Daniel Stenberg, see COPYING.curl for license details |
|
334 |
+ * Older style progress bar callback shim; for libcurl older than 7.32.0 ( CURLOPT_PROGRESSFUNCTION ). |
|
335 |
+ */ |
|
336 |
+static int older_progress(void *prog, |
|
337 |
+ double TotalToDownload, double NowDownloaded, |
|
338 |
+ double TotalToUpload, double NowUploaded) |
|
339 |
+{ |
|
340 |
+ return xferinfo(prog, |
|
341 |
+ (curl_off_t)TotalToDownload, |
|
342 |
+ (curl_off_t)NowDownloaded, |
|
343 |
+ (curl_off_t)TotalToUpload, |
|
344 |
+ (curl_off_t)NowUploaded); |
|
345 |
+} |
|
346 |
+#endif |
|
347 |
+ |
|
229 | 348 |
static fc_error_t create_curl_handle( |
230 | 349 |
int bHttp, |
231 | 350 |
int bAllowRedirect, |
... | ... |
@@ -233,8 +353,11 @@ static fc_error_t create_curl_handle( |
233 | 233 |
{ |
234 | 234 |
fc_error_t status = FC_EARG; |
235 | 235 |
|
236 |
- CURL *curl = NULL; |
|
236 |
+ CURL *curl = NULL; |
|
237 |
+ |
|
238 |
+#if defined(CURLOPT_DNS_LOCAL_IP4) || defined(CURLOPT_DNS_LOCAL_IP4) |
|
237 | 239 |
CURLcode curl_ret = CURLE_OK; |
240 |
+#endif |
|
238 | 241 |
|
239 | 242 |
char userAgent[128]; |
240 | 243 |
|
... | ... |
@@ -485,6 +608,7 @@ static fc_error_t remote_cvdhead( |
485 | 485 |
CURLcode curl_ret; |
486 | 486 |
char errbuf[CURL_ERROR_SIZE]; |
487 | 487 |
struct curl_slist *slist = NULL; |
488 |
+ struct xfer_progress prog; |
|
488 | 489 |
|
489 | 490 |
long http_code = 0; |
490 | 491 |
|
... | ... |
@@ -519,6 +643,45 @@ static fc_error_t remote_cvdhead( |
519 | 519 |
goto done; |
520 | 520 |
} |
521 | 521 |
|
522 |
+ if (mprintf_progress) { |
|
523 |
+ prog.lastRunTime = 0; |
|
524 |
+ prog.curl = curl; |
|
525 |
+ prog.bComplete = 0; |
|
526 |
+ |
|
527 |
+#if LIBCURL_VERSION_NUM >= 0x072000 |
|
528 |
+ /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will |
|
529 |
+ compile as they won't have the symbols around. |
|
530 |
+ |
|
531 |
+ If built with a newer libcurl, but running with an older libcurl: |
|
532 |
+ curl_easy_setopt() will fail in run-time trying to set the new |
|
533 |
+ callback, making the older callback get used. |
|
534 |
+ |
|
535 |
+ New libcurls will prefer the new callback and instead use that one even |
|
536 |
+ if both callbacks are set. */ |
|
537 |
+ |
|
538 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo)) { |
|
539 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
540 |
+ } |
|
541 |
+ /* pass the struct pointer into the xferinfo function, note that this is |
|
542 |
+ an alias to CURLOPT_PROGRESSDATA */ |
|
543 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog)) { |
|
544 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
545 |
+ } |
|
546 |
+#else |
|
547 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress)) { |
|
548 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
549 |
+ } |
|
550 |
+ /* pass the struct pointer into the progress function */ |
|
551 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog)) { |
|
552 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
553 |
+ } |
|
554 |
+#endif |
|
555 |
+ |
|
556 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L)) { |
|
557 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
558 |
+ } |
|
559 |
+ } |
|
560 |
+ |
|
522 | 561 |
if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_URL, url)) { |
523 | 562 |
logg("!remote_cvdhead: Failed to set CURLOPT_URL for curl session (%s).\n", url); |
524 | 563 |
status = FC_EFAILEDGET; |
... | ... |
@@ -715,6 +878,7 @@ static fc_error_t downloadFile( |
715 | 715 |
CURLcode curl_ret; |
716 | 716 |
char errbuf[CURL_ERROR_SIZE]; |
717 | 717 |
struct curl_slist *slist = NULL; |
718 |
+ struct xfer_progress prog; |
|
718 | 719 |
|
719 | 720 |
long http_code = 0; |
720 | 721 |
|
... | ... |
@@ -737,6 +901,45 @@ static fc_error_t downloadFile( |
737 | 737 |
goto done; |
738 | 738 |
} |
739 | 739 |
|
740 |
+ if (mprintf_progress) { |
|
741 |
+ prog.lastRunTime = 0; |
|
742 |
+ prog.curl = curl; |
|
743 |
+ prog.bComplete = 0; |
|
744 |
+ |
|
745 |
+#if LIBCURL_VERSION_NUM >= 0x072000 |
|
746 |
+ /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will |
|
747 |
+ compile as they won't have the symbols around. |
|
748 |
+ |
|
749 |
+ If built with a newer libcurl, but running with an older libcurl: |
|
750 |
+ curl_easy_setopt() will fail in run-time trying to set the new |
|
751 |
+ callback, making the older callback get used. |
|
752 |
+ |
|
753 |
+ New libcurls will prefer the new callback and instead use that one even |
|
754 |
+ if both callbacks are set. */ |
|
755 |
+ |
|
756 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo)) { |
|
757 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
758 |
+ } |
|
759 |
+ /* pass the struct pointer into the xferinfo function, note that this is |
|
760 |
+ an alias to CURLOPT_PROGRESSDATA */ |
|
761 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog)) { |
|
762 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
763 |
+ } |
|
764 |
+#else |
|
765 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress)) { |
|
766 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
767 |
+ } |
|
768 |
+ /* pass the struct pointer into the progress function */ |
|
769 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog)) { |
|
770 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
771 |
+ } |
|
772 |
+#endif |
|
773 |
+ |
|
774 |
+ if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L)) { |
|
775 |
+ logg("!create_curl_handle: Failed to set SSL CTX function!\n"); |
|
776 |
+ } |
|
777 |
+ } |
|
778 |
+ |
|
740 | 779 |
if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_URL, url)) { |
741 | 780 |
logg("!downloadFile: Failed to set CURLOPT_URL for curl session (%s).\n", url); |
742 | 781 |
} |
... | ... |
@@ -1761,11 +1964,22 @@ fc_error_t updatedb( |
1761 | 1761 |
goto done; |
1762 | 1762 |
} |
1763 | 1763 |
|
1764 |
+ if (mprintf_progress) { |
|
1765 |
+ if (remoteVersion - localVersion == 1) { |
|
1766 |
+ mprintf("Current database is 1 version behind.\n"); |
|
1767 |
+ } else { |
|
1768 |
+ mprintf("Current database is %u versions behind.\n", remoteVersion - localVersion); |
|
1769 |
+ } |
|
1770 |
+ } |
|
1764 | 1771 |
for (i = localVersion + 1; i <= remoteVersion; i++) { |
1765 | 1772 |
for (j = 1; j <= g_maxAttempts; j++) { |
1766 | 1773 |
int llogerr = logerr; |
1767 | 1774 |
if (logerr) |
1768 | 1775 |
llogerr = (j == g_maxAttempts); |
1776 |
+ |
|
1777 |
+ if (mprintf_progress) { |
|
1778 |
+ mprintf("Downloading database patch # %u...\n", i); |
|
1779 |
+ } |
|
1769 | 1780 |
ret = downloadPatch(database, tmpdir, i, server, llogerr); |
1770 | 1781 |
if (ret == FC_ECONNECTION || ret == FC_EFAILEDGET) { |
1771 | 1782 |
continue; |
... | ... |
@@ -1846,7 +2060,7 @@ fc_error_t updatedb( |
1846 | 1846 |
} |
1847 | 1847 |
} |
1848 | 1848 |
|
1849 |
- /* |
|
1849 |
+/* |
|
1850 | 1850 |
* Replace original database with new database. |
1851 | 1851 |
*/ |
1852 | 1852 |
#ifdef _WIN32 |