Modify zckdl so it does the curl calls itself
authorJonathan Dieter <jdieter@gmail.com>
Mon, 4 Jun 2018 07:48:16 +0000 (10:48 +0300)
committerJonathan Dieter <jdieter@gmail.com>
Mon, 4 Jun 2018 07:48:16 +0000 (10:48 +0300)
Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
src/zck_dl.c

index 1b81881d6a4eb9cc677ccc0b52cdc8319fce5ce9..b5dc65dc8bb1d32db09d122f0431b561e875dcfa 100644 (file)
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <argp.h>
 #include <zck.h>
+#include <curl/curl.h>
 
 #include "util_common.h"
 
@@ -103,13 +104,99 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
 static struct argp argp = {options, parse_opt, args_doc, doc};
 
-int main (int argc, char *argv[]) {
-    zckCtx *zck_tgt = zck_create();
+int dl_range(CURL *curl, zckDL *dl, char *url, char *range, int is_chunk) {
+    if(dl == NULL || dl->priv == NULL) {
+        printf("Struct not defined\n");
+        return 0;
+    }
 
-    if(zck_tgt == NULL)
-        exit(1);
+    CURLcode res;
+
+    zck_dl_reset(dl);
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, zck_header_cb);
+    curl_easy_setopt(curl, CURLOPT_HEADERDATA, dl);
+    if(is_chunk)
+        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, zck_write_chunk_cb);
+    else
+        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, zck_write_zck_header_cb);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, dl);
+    curl_easy_setopt(curl, CURLOPT_RANGE, range);
+    res = curl_easy_perform(curl);
+
+    if(res != CURLE_OK) {
+        printf("Download failed: %s\n", curl_easy_strerror(res));
+        return False;
+    }
+    long code;
+    curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code);
+    if (code != 206 && code != 200) {
+        printf("HTTP Error: %li when download %s\n", code,
+                url);
+        return False;
+    }
+
+    return True;
+}
+
+int dl_byte_range(CURL *curl, zckDL *dl, char *url, int start, int end) {
+    char *range = zck_get_range(start, end);
+    return dl_range(curl, dl, url, range, 0);
+}
+
+int dl_bytes(CURL *curl, zckDL *dl, char *url, size_t bytes, size_t start, size_t *buffer_len, int log_level) {
+    if(start + bytes > *buffer_len) {
+        int fd = zck_get_fd(dl->zck);
+
+        if(lseek(fd, 0, SEEK_END) == -1) {
+            printf("Seek to end of temporary file failed: %s\n",
+                   strerror(errno));
+            return 0;
+        }
+        if(*buffer_len >= start + bytes)
+            return 1;
+        if(!dl_byte_range(curl, dl, url, *buffer_len,
+                          (start + bytes - *buffer_len) - 1)) {
+            printf("Error downloading bytes\n");
+            return 0;
+        }
+        if(log_level <= ZCK_LOG_DEBUG)
+            printf("Downloading %lu bytes at position %lu\n",
+                   start+bytes-*buffer_len, *buffer_len);
+        *buffer_len += start + bytes - *buffer_len;
+        if(lseek(fd, start, SEEK_SET) == -1) {
+            printf("Seek to byte %lu of temporary file failed: %s\n", start,
+                   strerror(errno));
+            return 0;
+        }
+    }
+    return 1;
+}
+
+int dl_header(CURL *curl, zckDL *dl, char *url, int log_level) {
+    size_t buffer_len = 0;
+    size_t start = 0;
+
+    /* Download first two hundred bytes and read magic and hash type */
+    if(!dl_bytes(curl, dl, url, get_min_download_size(), start, &buffer_len, log_level))
+        return 0;
+    if(!zck_read_lead(dl->zck))
+        return 0;
+    start = zck_get_lead_length(dl->zck);
+    printf("Now we need %lu bytes\n", zck_get_header_length(dl->zck) - start);
+
+    if(!dl_bytes(curl, dl, url, zck_get_header_length(dl->zck) - start,
+                 start, &buffer_len, log_level))
+        return 0;
+    if(!zck_read_header(dl->zck))
+        return 0;
+    return 1;
+}
 
-    zck_dl_global_init();
+int main (int argc, char *argv[]) {
+    curl_global_init(CURL_GLOBAL_ALL);
 
     struct arguments arguments = {0};
 
@@ -132,11 +219,6 @@ int main (int argc, char *argv[]) {
         exit(1);
     }
 
-    zckDL *dl = zck_dl_init();
-    if(dl == NULL)
-        exit(1);
-    dl->zck = zck_tgt;
-
     char *outname_full = calloc(1, strlen(arguments.args[0])+1);
     memcpy(outname_full, arguments.args[0], strlen(arguments.args[0]));
     char *outname = basename(outname_full);
@@ -147,27 +229,33 @@ int main (int argc, char *argv[]) {
         exit(1);
     }
     free(outname_full);
-    dl->dst_fd = dst_fd;
+    zckCtx *zck_tgt = zck_init_adv_read(dst_fd);
+    if(zck_tgt == NULL)
+        exit(1);
 
-    if(!zck_dl_get_header(zck_tgt, dl, arguments.args[0]))
+    CURL *curl_ctx = curl_easy_init();
+    if(!curl_ctx) {
+        printf("Unable to allocate %lu bytes for curl context\n",
+                sizeof(CURL));
         exit(1);
+    }
 
-    zck_range_close(&(dl->info));
-    if(!zck_dl_copy_src_chunks(&(dl->info), zck_src, zck_tgt))
+    zckDL *dl = zck_dl_init(zck_tgt);
+    if(dl == NULL)
         exit(1);
-    int max_ranges = 256;
-    if(!zck_range_calc_segments(&(dl->info), max_ranges))
+    dl->zck = zck_tgt;
+
+    if(!dl_header(curl_ctx, dl, arguments.args[0], arguments.log_level))
         exit(1);
 
-    lseek(dl->dst_fd, 0, SEEK_SET);
-    if(!zck_dl_range(dl, arguments.args[0]))
+    if(!zck_copy_chunks(zck_src, zck_tgt))
         exit(1);
 
 
     printf("Downloaded %lu bytes\n",
            (long unsigned)zck_dl_get_bytes_downloaded(dl));
     int exit_val = 0;
-    switch(zck_hash_check_data(dl->zck, dl->dst_fd)) {
+    switch(zck_validate_data_checksum(dl->zck)) {
         case -1:
             exit_val = 1;
             break;
@@ -180,6 +268,7 @@ int main (int argc, char *argv[]) {
     zck_dl_free(&dl);
     zck_free(&zck_tgt);
     zck_free(&zck_src);
-    zck_dl_global_cleanup();
+    curl_easy_cleanup(curl_ctx);
+    curl_global_cleanup();
     exit(exit_val);
 }