aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/core/artifactory.c7
-rw-r--r--src/lib/core/download.c102
-rw-r--r--src/lib/core/strlist.c5
-rw-r--r--src/lib/delivery/delivery_conda.c5
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 {