diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/core/artifactory.c | 7 | ||||
| -rw-r--r-- | src/lib/core/download.c | 102 | ||||
| -rw-r--r-- | src/lib/core/strlist.c | 5 | ||||
| -rw-r--r-- | src/lib/delivery/delivery_conda.c | 5 |
4 files changed, 83 insertions, 36 deletions
diff --git a/src/lib/core/artifactory.c b/src/lib/core/artifactory.c index eedaf43..d5457e7 100644 --- a/src/lib/core/artifactory.c +++ b/src/lib/core/artifactory.c @@ -61,9 +61,10 @@ int artifactory_download_cli(char *dest, } sprintf(path + strlen(path), "/%s", remote_filename); - long fetch_status = download(url, path, NULL); - if (HTTP_ERROR(fetch_status) || fetch_status < 0) { - fprintf(stderr, "%s: download failed: %s\n", __FUNCTION__, url); + char *errmsg = NULL; + long fetch_status = download(url, path, &errmsg); + if (HTTP_ERROR(fetch_status)) { + SYSERROR("download failed: %s: %s\n", errmsg, url); return -1; } chmod(path, 0755); diff --git a/src/lib/core/download.c b/src/lib/core/download.c index b021860..817e576 100644 --- a/src/lib/core/download.c +++ b/src/lib/core/download.c @@ -13,45 +13,85 @@ size_t download_writer(void *fp, size_t size, size_t nmemb, void *stream) { long download(char *url, const char *filename, char **errmsg) { long http_code = -1; char user_agent[20]; - sprintf(user_agent, "stasis/%s", VERSION); + snprintf(user_agent, sizeof(user_agent), "stasis/%s", VERSION); + long timeout = 30L; - char *timeout_str = getenv("STASIS_DOWNLOAD_TIMEOUT"); + const char *timeout_str = getenv("STASIS_DOWNLOAD_TIMEOUT"); + if (timeout_str) { + timeout = strtol(timeout_str, NULL, 10); + if (timeout <= 0L) { + timeout = 1L; + } + } + + ssize_t max_retries = 5; + const char *max_retries_str = getenv("STASIS_DOWNLOAD_RETRY_MAX"); + if (max_retries_str) { + max_retries = strtol(max_retries_str, NULL, 10); + if (max_retries <= 0) { + max_retries = 1; + } + } + + ssize_t max_retry_seconds = 3; + const char *max_retry_seconds_str = getenv("STASIS_DOWNLOAD_RETRY_SECONDS"); + if (max_retry_seconds_str) { + max_retry_seconds = strtol(max_retry_seconds_str, NULL, 10); + if (max_retry_seconds < 0) { + max_retry_seconds = 0; + } + } + curl_global_init(CURL_GLOBAL_ALL); CURL *c = curl_easy_init(); - curl_easy_setopt(c, CURLOPT_URL, url); - curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, download_writer); - FILE *fp = fopen(filename, "wb"); - if (!fp) { - return -1; - } + for (ssize_t retry = 0; retry < max_retries; retry++) { + if (retry) { + fprintf(stderr, "[RETRY %zu/%zu] %s: %s\n", retry + 1, max_retries, *errmsg, url); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, download_writer); + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return -1; + } - curl_easy_setopt(c, CURLOPT_VERBOSE, 0L); - curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(c, CURLOPT_USERAGENT, user_agent); - curl_easy_setopt(c, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(c, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(c, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_USERAGENT, user_agent); + curl_easy_setopt(c, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(c, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, timeout); - if (timeout_str) { - timeout = strtol(timeout_str, NULL, 10); - } - curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, timeout); - - SYSDEBUG("curl_easy_perform(): \n\turl=%s\n\tfilename=%s\n\tuser agent=%s\n\ttimeout=%zu", url, filename, user_agent, timeout); - CURLcode curl_code = curl_easy_perform(c); - SYSDEBUG("curl status code: %d", curl_code); - if (curl_code != CURLE_OK) { - if (!*errmsg) { - *errmsg = strdup(curl_easy_strerror(curl_code)); - } else { - strncpy(*errmsg, curl_easy_strerror(curl_code), strlen(curl_easy_strerror(curl_code) + 1)); + SYSDEBUG("curl_easy_perform(): \n\turl=%s\n\tfilename=%s\n\tuser agent=%s\n\ttimeout=%zu", url, filename, user_agent, timeout); + CURLcode curl_code = curl_easy_perform(c); + SYSDEBUG("curl status code: %d", curl_code); + + if (curl_code != CURLE_OK) { + const size_t errmsg_maxlen = 256; + if (!*errmsg) { + *errmsg = calloc(errmsg_maxlen, sizeof(char)); + } + snprintf(*errmsg, errmsg_maxlen, "%s", curl_easy_strerror(curl_code)); + curl_easy_reset(c); + fclose(fp); + sleep(max_retry_seconds); + continue; + } + + // Data written. Clean up. + fclose(fp); + + if (CURLE_OK && *errmsg) { + // Retry loop succeeded, no error + *errmsg[0] = '\0'; } - goto failed; + + curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &http_code); + SYSDEBUG("HTTP code: %li", http_code); + + break; } - curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &http_code); - failed: - SYSDEBUG("HTTP code: %li", http_code); - fclose(fp); curl_easy_cleanup(c); curl_global_cleanup(); return http_code; diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c index 5655da9..a0db5f3 100644 --- a/src/lib/core/strlist.c +++ b/src/lib/core/strlist.c @@ -92,8 +92,11 @@ int strlist_append_file(struct StrList *pStrList, char *_path, ReaderFn *readerF } close(fd); filename = strdup(tempfile); - long http_code = download(path, filename, NULL); + char *errmsg = NULL; + long http_code = download(path, filename, &errmsg); if (HTTP_ERROR(http_code)) { + SYSERROR("%s: %s", errmsg, filename); + guard_free(errmsg); retval = -1; goto fatal; } diff --git a/src/lib/delivery/delivery_conda.c b/src/lib/delivery/delivery_conda.c index 8974ae8..191d93f 100644 --- a/src/lib/delivery/delivery_conda.c +++ b/src/lib/delivery/delivery_conda.c @@ -26,9 +26,12 @@ int delivery_get_conda_installer(struct Delivery *ctx, char *installer_url) { sprintf(script_path, "%s/%s", ctx->storage.tmpdir, installer); if (access(script_path, F_OK)) { // Script doesn't exist - long fetch_status = download(installer_url, script_path, NULL); + char *errmsg = NULL; + long fetch_status = download(installer_url, script_path, &errmsg); if (HTTP_ERROR(fetch_status) || fetch_status < 0) { // download failed + SYSERROR("download failed: %s: %s\n", errmsg, installer_url); + guard_free(errmsg); return -1; } } else { |
