#include <pakfire/mirrorlist.h>
#include <pakfire/progress.h>
+typedef enum pakfire_xfer_error_code {
+ PAKFIRE_XFER_OK = 0,
+
+ // General/Unknown Failure
+ PAKFIRE_XFER_FAILED,
+
+ // An unsupported protocol was requested
+ PAKFIRE_XFER_UNSUPPORTED,
+
+ // Invalid URL
+ PAKFIRE_XFER_INVALID_URL,
+
+ // The server responded with something weird
+ PAKFIRE_XFER_INVALID_RESPONSE,
+
+ // DNS Problem
+ PAKFIRE_XFER_DNS_ERROR,
+
+ // Authentication
+ PAKFIRE_XFER_AUTH_ERROR,
+ PAKFIRE_XFER_ACCESS_DENIED,
+
+ // Some connection problem
+ PAKFIRE_XFER_TRANSPORT_ERROR,
+
+ // Timeout
+ PAKFIRE_XFER_TIMEOUT,
+
+ // Local operation errors
+ PAKFIRE_XFER_WRITE_ERROR,
+ PAKFIRE_XFER_READ_ERROR,
+ PAKFIRE_XFER_ABORTED,
+
+ // Digest Mismatch
+ PAKFIRE_XFER_DIGEST_MISMATCH,
+} pakfire_xfer_error_code_t;
+
typedef enum pakfire_xfer_flags {
PAKFIRE_XFER_NO_PROGRESS = (1 << 0),
} pakfire_xfer_flags_t;
int pakfire_xfer_auth(struct pakfire_xfer* xfer);
int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* progress, int flags);
-int pakfire_xfer_done(struct pakfire_xfer* xfer, int code);
-int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code);
+pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code);
+int pakfire_xfer_fail(struct pakfire_xfer* xfer);
-int pakfire_xfer_run(struct pakfire_xfer* xfer, int flags);
-int pakfire_xfer_run_api_request(struct pakfire_xfer* xfer, struct json_object** response);
+pakfire_xfer_error_code_t pakfire_xfer_run(struct pakfire_xfer* xfer, int flags);
+pakfire_xfer_error_code_t pakfire_xfer_run_api_request(
+ struct pakfire_xfer* xfer, struct json_object** response);
#endif /* PAKFIRE_PRIVATE */
#endif /* PAKFIRE_XFER_H */
return 0;
}
-int pakfire_xfer_fail(struct pakfire_xfer* xfer, int code) {
+/*
+ This function translates any cURL error codes into xfer codes
+*/
+static pakfire_xfer_error_code_t pakfire_xfer_code(CURLcode code, int http_status) {
+ switch (code) {
+ case CURLE_OK:
+ return PAKFIRE_XFER_OK;
+
+ // Unsupported requests
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ case CURLE_NOT_BUILT_IN:
+ case CURLE_RANGE_ERROR:
+ return PAKFIRE_XFER_UNSUPPORTED;
+
+ // Invalid requests
+ case CURLE_URL_MALFORMAT:
+ return PAKFIRE_XFER_INVALID_URL;
+
+ // Invalid responses
+ case CURLE_TOO_MANY_REDIRECTS:
+ case CURLE_GOT_NOTHING:
+ case CURLE_BAD_CONTENT_ENCODING:
+ return PAKFIRE_XFER_INVALID_RESPONSE;
+
+ // DNS Errors
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_FTP_CANT_GET_HOST:
+ return PAKFIRE_XFER_DNS_ERROR;
+
+ // Authentication
+ case CURLE_AUTH_ERROR:
+ return PAKFIRE_XFER_AUTH_ERROR;
+
+ // Transport Errors
+ case CURLE_PROXY:
+ case CURLE_SSL_CONNECT_ERROR:
+ case CURLE_SSL_CERTPROBLEM:
+ case CURLE_SSL_CIPHER:
+ case CURLE_PEER_FAILED_VERIFICATION:
+ return PAKFIRE_XFER_TRANSPORT_ERROR;
+
+ // Access Denied
+ case CURLE_REMOTE_ACCESS_DENIED:
+ return PAKFIRE_XFER_ACCESS_DENIED;
+
+ // Timeout
+ case CURLE_FTP_ACCEPT_TIMEOUT:
+ case CURLE_OPERATION_TIMEDOUT:
+ return PAKFIRE_XFER_TIMEOUT;
+
+ // Write error
+ case CURLE_WRITE_ERROR:
+ return PAKFIRE_XFER_WRITE_ERROR;
+
+ // Read error
+ case CURLE_READ_ERROR:
+ case CURLE_FILE_COULDNT_READ_FILE:
+ return PAKFIRE_XFER_READ_ERROR;
+
+ // Aborted
+ case CURLE_ABORTED_BY_CALLBACK:
+ return PAKFIRE_XFER_ABORTED;
+
+ // HTTP Errors
+ case CURLE_HTTP_RETURNED_ERROR:
+ switch (http_status) {
+ // Proxy Error
+ case 502:
+ return PAKFIRE_XFER_TRANSPORT_ERROR;
+
+ // Service Unavailable
+ case 503:
+ return PAKFIRE_XFER_TRANSPORT_ERROR;
+
+ default:
+ return PAKFIRE_XFER_FAILED;
+ }
+ break;
+
+ // Return "unknown error" for any other codes
+ default:
+ return PAKFIRE_XFER_FAILED;
+ }
+}
+
+int pakfire_xfer_fail(struct pakfire_xfer* xfer) {
int r;
CTX_DEBUG(xfer->ctx, "Xfer failed\n");
pakfire_mirror_xfer_failed(xfer->mirror);
// Try again with another mirror
- return EAGAIN;
+ return -EAGAIN;
}
return 0;
}
-int pakfire_xfer_done(struct pakfire_xfer* xfer, int code) {
+pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code) {
CURL* h = xfer->handle;
int r;
- char* scheme = NULL;
+ const char* scheme = NULL;
long response_code;
long http_version;
double total_time;
if (r)
return r;
- CTX_DEBUG(xfer->ctx, "cURL xfer done: %d - %s\n",
- code, curl_easy_strerror(code));
-
- // Finish message digest computation
- if (xfer->evp) {
- r = EVP_DigestFinal_ex(xfer->evp, xfer->computed_digest, &xfer->computed_digest_length);
- if (r != 1) {
- CTX_ERROR(xfer->ctx, "Could not finish message digest computation: %s\n",
- ERR_error_string(ERR_get_error(), NULL));
- return 1;
- }
- }
+ // Log the result
+ CTX_DEBUG(xfer->ctx, "cURL xfer done: %d - %s\n", code, curl_easy_strerror(code));
+ if (*xfer->error)
+ CTX_DEBUG(xfer->ctx, " Error: %s\n", xfer->error);
// Protocol
curl_easy_getinfo(h, CURLINFO_SCHEME, &scheme);
if (upload_speed)
CTX_DEBUG(xfer->ctx, " Upload Speed: %ld bps\n", upload_speed);
- // Message Digest
- char* hexdigest = __pakfire_hexlify(xfer->computed_digest, xfer->computed_digest_length);
- if (hexdigest && *hexdigest) {
- CTX_DEBUG(xfer->ctx, " Message Digest: %s\n", hexdigest);
- free(hexdigest);
- }
-
// Check if digests match
if (xfer->evp) {
+ // Finish message digest computation
+ r = EVP_DigestFinal_ex(xfer->evp, xfer->computed_digest, &xfer->computed_digest_length);
+ if (r != 1) {
+ CTX_ERROR(xfer->ctx, "Could not finish message digest computation: %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ return 1;
+ }
+
+ // Message Digest
+ char* hexdigest = __pakfire_hexlify(xfer->computed_digest, xfer->computed_digest_length);
+ if (hexdigest) {
+ CTX_DEBUG(xfer->ctx, " Message Digest: %s\n", hexdigest);
+ free(hexdigest);
+ }
+
r = CRYPTO_memcmp(xfer->computed_digest, xfer->expected_digest,
xfer->computed_digest_length);
- // If they don't match, log an error and try again
+ // If they don't match, log the error
if (r) {
char* computed_hexdigest = __pakfire_hexlify(xfer->computed_digest,
xfer->computed_digest_length);
free(expected_hexdigest);
// Make this download fail
- r = pakfire_xfer_fail(xfer, 0);
+ r = pakfire_xfer_fail(xfer);
if (r)
return r;
- return 1;
+ return PAKFIRE_XFER_DIGEST_MISMATCH;
}
}
- // If we could not determine the scheme...
- if (!scheme)
- r = pakfire_xfer_fail(xfer, 0);
-
- // FILE
- else if (strcmp(scheme, "FILE") == 0) {
- // Handle any errors
- if (code)
- r = pakfire_xfer_fail(xfer, code);
- else
- r = pakfire_xfer_save(xfer);
-
- return r;
-
- // HTTPS + HTTP
- } else if ((strcmp(scheme, "HTTPS") == 0) || (strcmp(scheme, "HTTP") == 0)) {
- switch (response_code) {
- // 200 - OK
- case 200:
- r = pakfire_xfer_save(xfer);
- if (r)
- return r;
- break;
-
- // Treat all other response codes as an error
- default:
- r = pakfire_xfer_fail(xfer, code);
- if (r)
- return r;
-
- // Error
- return 1;
- }
-
- // FTP
- } else if (strcmp(scheme, "FTP") == 0) {
- if (response_code == 226)
- r = pakfire_xfer_save(xfer);
- else
- r = pakfire_xfer_fail(xfer, code);
+ // Handle any errors
+ if (code) {
+ r = pakfire_xfer_fail(xfer);
+ if (r)
+ return r;
- return r;
+ // Report that something went wrong
+ return pakfire_xfer_code(code, response_code);
}
- // Success
- return 0;
+ // Otherwise save the file
+ return pakfire_xfer_save(xfer);
}
static int pakfire_xfer_update(void* data,
return 0;
}
-int pakfire_xfer_run(struct pakfire_xfer* xfer, int flags) {
+pakfire_xfer_error_code_t pakfire_xfer_run(struct pakfire_xfer* xfer, int flags) {
int r;
-AGAIN:
// Prepare the xfer
r = pakfire_xfer_prepare(xfer, NULL, flags);
if (r) {
// Handle the result
r = pakfire_xfer_done(xfer, r);
- // Repeat the xfer if asked
- switch (-r) {
- case EAGAIN:
- goto AGAIN;
-
- default:
- break;
- }
+ // Repeat if asked
+ if (r == -EAGAIN)
+ return pakfire_xfer_run(xfer, flags);
return r;
}
return r;
}
-static int pakfire_xfer_run_api_request_once(struct pakfire_xfer* xfer, struct json_object** response) {
+static pakfire_xfer_error_code_t pakfire_xfer_run_api_request_once(
+ struct pakfire_xfer* xfer, struct json_object** response) {
char* buffer = NULL;
size_t length = 0;
int r;
This function sends a request and automatically parses the response.
The response might optionally be returned if response is not NULL.
*/
-int pakfire_xfer_run_api_request(struct pakfire_xfer* xfer, struct json_object** response) {
- int r;
+pakfire_xfer_error_code_t pakfire_xfer_run_api_request(
+ struct pakfire_xfer* xfer, struct json_object** response) {
+ pakfire_xfer_error_code_t r;
// Loop indefinitely...
for (;;) {