}
int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path) {
+ int r;
+
if (!path || !*path) {
errno = EINVAL;
return 1;
struct json_object* mirrors = NULL;
// Check if we found a valid mirrorlist
- int r = pakfire_mirrorlist_check_mirrorlist(list, json);
+ r = pakfire_mirrorlist_check_mirrorlist(list, json);
if (r)
goto ERROR;
return list->num_mirrors == 0;
}
+/*
+ Return the first mirror that isn't broken
+*/
struct pakfire_mirror* pakfire_mirrorlist_get_first(struct pakfire_mirrorlist* list) {
- if (!list->num_mirrors)
- return NULL;
+ for (unsigned int i = 0; i < list->num_mirrors; i++) {
+ if (pakfire_mirror_is_broken(list->mirrors[i]))
+ continue;
+
+ return pakfire_mirror_ref(list->mirrors[i]);
+ }
- return pakfire_mirror_ref(list->mirrors[0]);
+ return NULL;
}
struct pakfire_mirror* pakfire_mirrorlist_get_next(
struct pakfire_mirrorlist* list, struct pakfire_mirror* mirror) {
+ // Return NULL if we have reached the end of the list
+ if (!mirror)
+ return NULL;
+
+ int found = 0;
+
+ // Walk through all mirrors until we have found the current one
for (unsigned int i = 0; i < list->num_mirrors; i++) {
- if (list->mirrors[i] == mirror) {
- if (i < list->num_mirrors)
- return list->mirrors[i+1];
+ if (!found) {
+ // Set found once we found our mirror
+ if (list->mirrors[i] == mirror)
+ found = 1;
- break;
+ continue;
}
+
+ // Skip any broken mirrors
+ if (pakfire_mirror_is_broken(list->mirrors[i]))
+ continue;
+
+ // Return the mirror
+ return pakfire_mirror_ref(list->mirrors[i]);
}
return NULL;
}
int pakfire_xfer_set_mirrorlist(struct pakfire_xfer* xfer, struct pakfire_mirrorlist* mirrors) {
- if (xfer->mirrors)
+ // Drop all references to a former mirrorlist
+ if (xfer->mirrors) {
pakfire_mirrorlist_unref(xfer->mirrors);
+ xfer->mirrors = NULL;
+ }
+
+ // Drop all references to the formerly selected mirror
+ if (xfer->mirror) {
+ pakfire_mirror_unref(xfer->mirror);
+ xfer->mirror = NULL;
+ }
- xfer->mirrors = pakfire_mirrorlist_ref(mirrors);
+ // If a new list was passed, we store a reference to it
+ if (mirrors) {
+ xfer->mirrors = pakfire_mirrorlist_ref(mirrors);
+
+ // Select the first mirror from the list
+ xfer->mirror = pakfire_mirrorlist_get_first(xfer->mirrors);
+ }
return 0;
}
}
}
+static int pakfire_xfer_next_mirror(struct pakfire_xfer* xfer) {
+ struct pakfire_mirror* mirror = NULL;
+
+ // If our mirror is broken, we select the next one
+ if (xfer->mirror) {
+ // Choose the next mirror
+ mirror = pakfire_mirrorlist_get_next(xfer->mirrors, xfer->mirror);
+
+ // Free the previous mirror
+ pakfire_mirror_unref(xfer->mirror);
+
+ // Store the new mirror
+ if (mirror) {
+ DEBUG(xfer->ctx, "Selected mirror %s\n", pakfire_mirror_get_url(mirror));
+
+ xfer->mirror = pakfire_mirror_ref(mirror);
+
+ // If we could not find a mirror, we clear the pointer
+ } else {
+ xfer->mirror = NULL;
+ }
+ }
+
+ // Cleanup
+ if (mirror)
+ pakfire_mirror_unref(mirror);
+
+ return 0;
+}
+
static int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code) {
int r;
if (xfer->mirror) {
pakfire_mirror_xfer_failed(xfer->mirror);
+ // Select the next mirror
+ r = pakfire_xfer_next_mirror(xfer);
+ if (r < 0)
+ return r;
+
// Try again with another mirror
return -EAGAIN;
}
return code;
}
-static int pakfire_xfer_select_mirror(struct pakfire_xfer* xfer) {
- // Choose the next mirror
- if (xfer->mirror)
- xfer->mirror = pakfire_mirrorlist_get_next(xfer->mirrors, xfer->mirror);
-
- // If no mirror has been selected yet, choose the first one
- else
- xfer->mirror = pakfire_mirrorlist_get_first(xfer->mirrors);
-
- // Skip this mirror if it is broken
- while (xfer->mirror && pakfire_mirror_is_broken(xfer->mirror)) {
- // Move on to the next mirror
- xfer->mirror = pakfire_mirrorlist_get_next(xfer->mirrors, xfer->mirror);
- }
-
- // No mirror found
- if (!xfer->mirror) {
- ERROR(xfer->ctx, "No mirrors left to try\n");
-
- // No mirrors left
- return ENOENT;
- }
-
- DEBUG(xfer->ctx, "Selected mirror %s\n", pakfire_mirror_get_url(xfer->mirror));
-
- return 0;
-}
-
static const char* curl_http_version(long v) {
switch (v) {
#ifdef CURL_HTTP_VERSION_3_0
if (r)
goto ERROR;
- // Join path if we are using mirrors
- } else if (xfer->mirrors && !pakfire_mirrorlist_empty(xfer->mirrors)) {
- r = pakfire_xfer_select_mirror(xfer);
- if (r)
- goto ERROR;
-
+ // Join path if we are using a mirror
+ } else if (xfer->mirror) {
// Set the mirror's base URL first
r = curl_url_set(xfer->fullurl, CURLUPART_URL,
pakfire_mirror_get_url(xfer->mirror), 0);