#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Head.h"
#include "Aget.h"
#include "Misc.h"
#include "Download.h"
#include "Resume.h"
#include "Data.h"
extern struct thread_data *wthread;
extern struct request *req;
extern int fsuggested, nthreads;
extern int bwritten;
extern pthread_t hthread;
extern int errno;
void get(struct request *req)
{
int i, ret, fd, diff_sec, nok = 0;
long soffset, foffset;
char *fmt;
if (req->proto == PROTO_HTTP)
http_head_req(req);
/* According to the content-length, get the
* suggested number of threads to open.
* if the user insists on his value, let it be that way,
* use the user's value.
*/
ret = numofthreads(req->clength);
if (fsuggested == 0) {
if (ret == 0)
nthreads = 1;
else
nthreads = ret;
}
wthread = (struct thread_data *)malloc(nthreads * sizeof(struct thread_data));
Log("Downloading %s (%d bytes) from site %s(%s:%d). Number of Threads: %d",
req->url, req->clength, req->host, req->ip, req->port, nthreads);
if (strlen(req->lfile) != 0) {
if ((fd = open(req->lfile, O_CREAT | O_RDWR, S_IRWXU)) == -1) {
fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno));
exit(1);
}
} else {
if ((fd = open(req->file, O_CREAT | O_RDWR, S_IRWXU)) == -1) {
fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno));
exit(1);
}
}
if ((lseek(fd, req->clength - 1, SEEK_SET)) == -1) {
fprintf(stderr, "get: couldn't lseek: %s\n", strerror(errno));
exit(1);
}
if ((write(fd, "0", 1)) == -1) {
fprintf(stderr, "get: couldn't allocate space for download file: %s\n", strerror(errno));
exit(1);
}
/* Get the starting time, prepare GET format string, and start the threads */
fmt = (char *)calloc(GETREQSIZ - 2, sizeof(char));
time(&t_start);
for (i = 0; i < nthreads; i++) {
soffset = calc_offset(req->clength, i, nthreads);
foffset = calc_offset(req->clength, i + 1, nthreads);
wthread[i].soffset = soffset;
wthread[i].foffset = (i == nthreads - 1 ? req->clength : foffset);
wthread[i].sin.sin_family = AF_INET;
wthread[i].sin.sin_addr.s_addr = inet_addr(req->ip);
wthread[i].sin.sin_port = htons(req->port);
wthread[i].fd = dup(fd);
wthread[i].clength = req->clength;
snprintf(fmt, GETREQSIZ, GETREQ, req->url, req->host, PROGVERSION, soffset);
strncpy(wthread[i].getstr, fmt, GETREQSIZ);
pthread_create(&(wthread[i].tid), NULL, http_get, &(wthread[i]));
}
free(fmt);
/* Wait for all of the threads to finish...
*
* TODO: If a thread fails, restart that!
*/
for (i = 0; i < nthreads; i++) {
pthread_join(wthread[i].tid, NULL);
if (wthread[i].status == STAT_OK)
nok++;
}
if (nok == nthreads)
pthread_cancel(hthread);
else
pthread_join(hthread, NULL);
/* Get the finish time, derive some stats */
time(&t_finish);
if ((diff_sec = t_finish - t_start) == 0)
diff_sec = 1; /* Avoid division by zero */
Log("Download completed, job completed in %d seconds. (%d Kb/sec)",
diff_sec, (req->clength / diff_sec) / 1024);
Log("Shutting down...");
close(fd);
}
void resume_get(struct hist_data *h)
{
int i, fd, diff_sec, nok = 0;
char *fmt;
nthreads = h->nthreads;
fmt = (char *)calloc(GETREQSIZ - 2, sizeof(char));
wthread = (struct thread_data *)malloc(nthreads * sizeof(struct thread_data));
memcpy(req, &h->req, sizeof(struct request));
memcpy(wthread, h->wthread, sizeof(struct thread_data) * nthreads);
Log("Resuming download %s (%d bytes) from site %s(%s:%d). Number of Threads: %d",
req->url, req->clength, req->host, req->ip, req->port, nthreads);
if (strlen(req->lfile) != 0) {
if ((fd = open(req->lfile, O_RDWR, S_IRWXU)) == -1) {
fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno));
exit(1);
}
} else {
if ((fd = open(req->file, O_RDWR, S_IRWXU)) == -1) {
fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno));
exit(1);
}
}
time(&t_start);
#ifdef DEBUG
for (i = 0; i < nthreads; i++)
printf("Start: %ld, Finish: %ld, Offset: %ld, Diff: %ld\n",
wthread[i].soffset,
wthread[i].foffset,
wthread[i].offset,
wthread[i].offset - wthread[i].soffset);
#endif
for (i = 0; i < nthreads; i++) {
wthread[i].soffset = wthread[i].offset;
wthread[i].fd = dup(fd);
snprintf(fmt, GETREQSIZ, GETREQ, req->url, req->host, PROGVERSION, wthread[i].offset);
strncpy(wthread[i].getstr, fmt, GETREQSIZ);
pthread_create(&(wthread[i].tid), NULL, http_get, &(wthread[i]));
}
for (i = 0; i < nthreads; i++)
pthread_join(wthread[i].tid, NULL);
for (i = 0; i < nthreads; i++) {
pthread_join(wthread[i].tid, NULL);
if (wthread[i].status == STAT_OK)
nok++;
}
if (nok == nthreads)
pthread_cancel(hthread);
else
pthread_join(hthread, NULL);
time(&t_finish);
if ((diff_sec = t_finish - t_start) == 0)
diff_sec = 1; /* Avoid division by zero */
Log("Download completed, job completed in %d seconds. (%d Kb/sec)",
diff_sec, ((req->clength - h->bwritten) / diff_sec) / 1024);
Log("Shutting down...");
close(fd);
}
syntax highlighted by Code2HTML, v. 0.9.1