Compare commits

..

No commits in common. "master" and "v0.1" have entirely different histories.
master ... v0.1

165
gget.c
View File

@ -1,5 +1,5 @@
/*
Copyright 2014-2016 Grégory Soutadé
Copyright 2014 Grégory Soutadé
This file is part of gget.
@ -86,7 +86,6 @@ static int get_console_width()
typedef struct {
curl_off_t dltotal;
curl_off_t dlnow;
curl_off_t dllast;
unsigned speed;
} stats_t ;
@ -102,7 +101,6 @@ typedef struct {
unsigned already_downloaded;
unsigned start;
unsigned end;
unsigned max_chunk_size;
curl_off_t max_speed;
stats_t* stats;
} transfert_t;
@ -218,8 +216,8 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
curl_easy_getinfo(t->curl, CURLINFO_SPEED_DOWNLOAD, &speed_d);
t->stats[t->id].dlnow += (dlnow - t->stats[t->id].dllast);
t->stats[t->id].dllast = dlnow;
t->stats[t->id].dltotal = dltotal + t->already_downloaded;
t->stats[t->id].dlnow = dlnow + t->already_downloaded;
t->stats[t->id].speed = speed_d;
return 0;
@ -228,12 +226,14 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
void* do_transfert(transfert_t* t)
{
CURLcode res;
char range[64];
unsigned start, end, chunk_size;
char range[50];
snprintf(range, sizeof(range), "%u-%u", t->start, t->end);
curl_easy_setopt(t->curl, CURLOPT_USERAGENT, t->user_agent);
curl_easy_setopt(t->curl, CURLOPT_URL, t->url);
curl_easy_setopt(t->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
if (t->max_speed)
curl_easy_setopt(t->curl, CURLOPT_MAX_RECV_SPEED_LARGE, t->max_speed);
@ -248,37 +248,13 @@ void* do_transfert(transfert_t* t)
curl_easy_setopt(t->curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
curl_easy_setopt(t->curl, CURLOPT_XFERINFODATA, t);
start = t->start;
if (t->max_chunk_size && (t->end - t->start) > t->max_chunk_size)
chunk_size = t->max_chunk_size;
else
chunk_size = t->end - t->start;
end = start + chunk_size;
/* Perform the request, res will get the return code */
res = curl_easy_perform(t->curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
while (start < t->end)
{
snprintf(range, sizeof(range), "%u-%u", start, end);
curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
/* Perform the request, res will get the return code */
res = curl_easy_perform(t->curl);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
break;
}
start += chunk_size + 1;
if (t->max_chunk_size && (t->end - start) > t->max_chunk_size)
chunk_size = t->max_chunk_size;
else
chunk_size = t->end - start;
end = start + chunk_size;
t->stats[t->id].dllast = 0;
}
return NULL;
}
@ -286,7 +262,7 @@ static int configure_transfert(int id, transfert_t* t,
char* url, char* filename,
unsigned start, unsigned end,
unsigned max_speed, char* user_agent,
unsigned max_chunk_size, int* exists)
int* exists)
{
// filename + . + number + \0
unsigned filename_size = strlen(filename)+1+3+1;
@ -308,7 +284,6 @@ static int configure_transfert(int id, transfert_t* t,
t->end = end;
t->max_speed = max_speed;
t->user_agent = user_agent;
t->max_chunk_size = max_chunk_size;
if (stat(t->tmp_filename, &s))
{
@ -396,7 +371,6 @@ static int get_file_info(char* url, char* user_agent,
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
if (!quiet)
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
@ -478,14 +452,13 @@ static void find_free_file(char** filename)
static void usage(char* program_name)
{
printf("%s: Parallel HTTP file download\n", program_name);
printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-m max_chunk_size[kKmMgG]] [-q] [-h] url\n",
printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-q] [-h] url\n",
program_name);
printf("\t-n : Specify number of threads (default : %d)\n", DEFAULT_NB_THREADS);
printf("\t-l : Download speed limit for all threads (not per thread)\n");
printf("\t-o : Out filename, default is retrieved by GET request or '%s' if not found\n",
DEFAULT_OUT_FILENAME);
printf("\t-u : User agent, default is '%s'\n", DEFAULT_USER_AGENT);
printf("\t-m : Max chunk size in bytes\n");
printf("\t-q : Quiet mode\n");
printf("\t-h : Display help\n");
}
@ -494,15 +467,14 @@ int main(int argc, char** argv)
{
pthread_t display_thread = 0;
unsigned nb_threads = DEFAULT_NB_THREADS;
char* user_agent = strdup(DEFAULT_USER_AGENT), *endptr;
char* user_agent = strdup(DEFAULT_USER_AGENT);
stats_t* stats = NULL;
int ret = -1, i;
stats_params_t stats_params;
transfert_t* transferts = NULL;
unsigned total_size, thread_size, multiplier=1;
double displayed_size;
unsigned start, end, max_speed = 0, quiet = 0, max_chunk_size = 0;
char* out_filename = NULL, *url = NULL, c;
unsigned total_size, thread_size;
unsigned start, end, max_speed = 0, quiet = 0;
char* out_filename = NULL, *url = NULL;
char* suffix = "B";
void* res;
int opt;
@ -512,56 +484,10 @@ int main(int argc, char** argv)
int continuous_mode=0;
int exists;
while ((opt = getopt(argc, argv, "hl:m:n:o:qu:")) != -1) {
while ((opt = getopt(argc, argv, "hn:l:o:u:q")) != -1) {
switch (opt) {
case 'l':
max_speed = strtoul(optarg, &endptr, 0);
if (*endptr)
{
usage(argv[0]);
return 1;
}
break;
case 'm':
if (strlen(optarg) > 1)
{
c = optarg[strlen(optarg)-1];
if (c < '0' || c > '9')
{
switch(c)
{
case 'g':
case 'G':
multiplier *= 1024;
case 'm':
case 'M':
multiplier *= 1024;
case 'k':
case 'K':
multiplier *= 1024;
optarg[strlen(optarg)-1] = 0;
break;
default:
usage(argv[0]);
return 1;
}
}
}
max_chunk_size = strtoul(optarg, &endptr, 0);
if (*endptr)
{
usage(argv[0]);
return 1;
}
max_chunk_size *= multiplier;
break;
case 'n':
nb_threads = strtoul(optarg, &endptr, 0);
if (*endptr)
{
usage(argv[0]);
return 1;
}
nb_threads = atoi(optarg);
if (nb_threads == 0)
nb_threads = DEFAULT_NB_THREADS;
else if (nb_threads > MAX_NB_THREADS)
@ -570,15 +496,18 @@ int main(int argc, char** argv)
nb_threads = MAX_NB_THREADS;
}
break;
case 'l':
max_speed = atoi(optarg);
break;
case 'o':
out_filename = strdup(optarg);
break;
case 'q':
quiet = 1;
break;
case 'u':
user_agent = strdup(optarg);
break;
case 'q':
quiet = 1;
break;
default:
case 'h':
usage(argv[0]);
@ -610,29 +539,7 @@ int main(int argc, char** argv)
goto end;
}
else
{
displayed_size = (double)total_size;
suffix = "B";
if (displayed_size > (1024))
{
displayed_size /= 1024.0;
suffix = "kB";
}
if (displayed_size > (1024))
{
displayed_size /= 1024.0;
suffix = "MB";
}
if (displayed_size > (1024))
{
displayed_size /= 1024.0;
suffix = "GB";
}
printf("Save in '%s' (%.2f%s)\n\n", out_filename, displayed_size, suffix);
}
printf("Save in '%s'\n\n", out_filename);
stats = malloc(sizeof(*stats)*nb_threads);
memset(stats, 0, sizeof(*stats)*nb_threads);
@ -654,16 +561,10 @@ int main(int argc, char** argv)
end = total_size;
ret = configure_transfert(i, &transferts[i], url, out_filename,
start, end, max_speed, user_agent,
max_chunk_size, &exists);
start, end, max_speed, user_agent, &exists);
if (ret)
goto end;
transferts[i].stats[i].dltotal = transferts[i].already_downloaded +
(end - start);
transferts[i].stats[i].dlnow = transferts[i].already_downloaded;
transferts[i].stats[i].dllast = 0;
// First set continuous mode
if (i == 0)
{
@ -682,8 +583,7 @@ int main(int argc, char** argv)
// Check for last temporary file
configure_transfert(i, &transferts[i], url, out_filename,
start, end, max_speed, user_agent, max_chunk_size,
&exists);
start, end, max_speed, user_agent, &exists);
unlink(transferts[i].tmp_filename);
if (exists)
@ -765,8 +665,7 @@ end:
if (transferts)
free(transferts);
if (!quiet)
printf("\n");
printf("\n");
return ret;
}