static int curl_initialized = 0;
struct pakfire_mirror {
+ STAILQ_ENTRY(pakfire_mirror) nodes;
+
char url[PATH_MAX];
- unsigned int priority;
unsigned int retries_left;
int broken;
FILE* f;
// Mirrors
- int mirror;
+ struct pakfire_mirror* mirror;
};
struct pakfire_downloader {
TAILQ_HEAD(transfers, pakfire_transfer) transfers;
// Mirror stuff
+ STAILQ_HEAD(mirrors, pakfire_mirror) mirrors;
char baseurl[PATH_MAX];
- struct pakfire_mirror** mirrors;
- unsigned int num_mirrors;
};
static int pakfire_url_is_absolute(const char* url) {
}
static void pakfire_downloader_clear_mirrors(struct pakfire_downloader* downloader) {
- if (downloader->mirrors) {
- for (unsigned int i = 0; i < downloader->num_mirrors; i++) {
- free(downloader->mirrors[i]);
- }
-
- free(downloader->mirrors);
- downloader->num_mirrors = 0;
+ while (!STAILQ_EMPTY(&downloader->mirrors)) {
+ struct pakfire_mirror* mirror = STAILQ_FIRST(&downloader->mirrors);
+ STAILQ_REMOVE_HEAD(&downloader->mirrors, nodes);
+ free(mirror);
}
}
while (!TAILQ_EMPTY(&downloader->transfers)) {
transfer = TAILQ_LAST(&downloader->transfers, transfers);
TAILQ_REMOVE(&downloader->transfers, transfer, nodes);
+ pakfire_transfer_free(transfer);
}
// Free mirrors
// Init transfers queue
TAILQ_INIT(&d->transfers);
+ // Init mirrors
+ STAILQ_INIT(&d->mirrors);
+
// Setup cURL
int r = pakfire_downloader_setup_curl(d);
if (r)
snprintf(downloader->baseurl, sizeof(downloader->baseurl) - 1, "%s", baseurl);
}
-static int pakfire_downloader_mirrors_cmp(const void* ptr1, const void* ptr2) {
- struct pakfire_mirror* mirror1 = (struct pakfire_mirror*)ptr1;
- struct pakfire_mirror* mirror2 = (struct pakfire_mirror*)ptr2;
-
- if (mirror1->priority > mirror2->priority)
- return 1;
- else if (mirror1->priority < mirror2->priority)
- return -1;
- else
- return 0;
-}
-
-static void pakfire_downloader_mirrors_sort(struct pakfire_downloader* downloader) {
- if (!downloader->mirrors)
- return;
-
- qsort(downloader->mirrors, downloader->num_mirrors, sizeof(*downloader->mirrors),
- pakfire_downloader_mirrors_cmp);
-}
-
static int pakfire_downloader_check_mirrorlist(struct pakfire_downloader* downloader,
struct json_object* root) {
struct json_object* typeobj = NULL;
const char* url = json_object_get_string(urlobj);
// Add the mirror to the downloader
- r = pakfire_downloader_add_mirror(downloader, url, i);
+ r = pakfire_downloader_add_mirror(downloader, url);
if (r) {
ERROR(downloader->pakfire, "Could not add mirror %s: %s\n",
url, strerror(errno));
}
int pakfire_downloader_add_mirror(struct pakfire_downloader* downloader,
- const char* url, unsigned int priority) {
- // Make space for another mirror
- downloader->mirrors = reallocarray(downloader->mirrors,
- sizeof(*downloader->mirrors), downloader->num_mirrors + 1);
-
+ const char* url) {
// Allocate a new mirror object
struct pakfire_mirror* mirror = calloc(1, sizeof(*mirror));
if (!mirror)
return ENOMEM;
- // Copy attributes
+ // Copy URL
snprintf(mirror->url, sizeof(mirror->url) - 1, "%s", url);
- mirror->priority = priority;
// Set retries
mirror->retries_left = MIRROR_RETRIES;
// Append it to the list
- downloader->mirrors[downloader->num_mirrors++] = mirror;
-
- // Sort mirrors
- pakfire_downloader_mirrors_sort(downloader);
+ STAILQ_INSERT_TAIL(&downloader->mirrors, mirror, nodes);
DEBUG(downloader->pakfire, "Added mirror %s\n", mirror->url);
DEBUG(downloader->pakfire, "Adding download of %s\n", url);
// Do not allow relative URLs when no mirrors are set
- if (!pakfire_url_is_absolute(url) && downloader->num_mirrors == 0) {
+ if (!pakfire_url_is_absolute(url) && STAILQ_EMPTY(&downloader->mirrors)) {
ERROR(downloader->pakfire, "Relative URLs cannot be used without any mirrors set\n");
return EINVAL;
}
if (!transfer)
return ENOMEM;
- // Select no mirror
- transfer->mirror = -1;
-
// Copy URL
snprintf(transfer->url, sizeof(transfer->url) - 1, "%s", url);
static int pakfire_transfer_select_mirror(struct pakfire_downloader* downloader,
struct pakfire_transfer* transfer) {
- for (unsigned int next = transfer->mirror + 1;
- next < downloader->num_mirrors; next++) {
- struct pakfire_mirror* mirror = downloader->mirrors[next];
+ // Choose the next mirror
+ if (transfer->mirror)
+ transfer->mirror = STAILQ_NEXT(transfer->mirror, nodes);
- // Skip broken mirrors
- if (mirror->broken)
- continue;
+ // If no mirror has been selected yet, choose the first one
+ else
+ transfer->mirror = STAILQ_FIRST(&downloader->mirrors);
- DEBUG(downloader->pakfire, "Selected mirror %s\n", mirror->url);
- transfer->mirror = next;
+ // Skip this mirror if it is broken
+ while (transfer->mirror && transfer->mirror->broken) {
+ // Move on to the next mirror
+ transfer->mirror = STAILQ_NEXT(transfer->mirror, nodes);
+ }
+
+ // No mirror found
+ if (!transfer->mirror) {
+ ERROR(downloader->pakfire, "No mirrors left to try\n");
- return 0;
+ // No mirrors left
+ return ENOENT;
}
- ERROR(downloader->pakfire, "No mirrors left to try\n");
+ DEBUG(downloader->pakfire, "Selected mirror %s\n", transfer->mirror->url);
- // No mirrors left
- return ENOENT;
+ return 0;
}
static const char* curl_http_version(long v) {
return r;
// Did we use a mirror?
- if (transfer->mirror >= 0) {
- struct pakfire_mirror* mirror = downloader->mirrors[transfer->mirror];
-
+ if (transfer->mirror) {
// Decrease retries and potentially mark mirror as broken
- if (!mirror->retries_left--) {
- DEBUG(downloader->pakfire, "Consider mirror %s as broken\n", mirror->url);
- mirror->broken = 1;
+ if (!transfer->mirror->retries_left--) {
+ DEBUG(downloader->pakfire, "Mark mirror %s as broken\n",
+ transfer->mirror->url);
+ transfer->mirror->broken = 1;
}
// Try again with another mirror
if (r)
return r;
- struct pakfire_mirror* mirror = downloader->mirrors[transfer->mirror];
-
- char* url = pakfire_url_join(mirror->url, transfer->url);
+ char* url = pakfire_url_join(transfer->mirror->url, transfer->url);
if (!url) {
ERROR(downloader->pakfire, "Error composing download URL: %s\n",
strerror(errno));