summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.c104
1 files changed, 89 insertions, 15 deletions
diff --git a/src/main.c b/src/main.c
index 8678cf6..f6334e0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@
#include <limits.h>
#include <syslog.h>
#include <netinet/tcp.h>
+#include <fcntl.h>
#define TIP_TORRENT_PORT 9999
@@ -43,6 +44,7 @@ enum {
TIP_CLIENT_GET_HEADER,
TIP_CLIENT_GET_PAYLOAD,
TIP_CLIENT_POST_REDIRECT,
+ TIP_CLIENT_HEAD_HEADER,
TIP_CLIENT_DONE,
};
@@ -53,6 +55,7 @@ struct tip_client {
uint32_t buf_len;
uint64_t data_len;
uint64_t content_len;
+ uint64_t chunk_offset;
int state;
int num_retries;
int fd;
@@ -188,13 +191,7 @@ static int tip_client_get_hdr(struct tip_client *cli)
else
tip_client_stats.direct_from_server++;
- cli->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (cli->fd < 0) {
- syslog(LOG_ERR, "failed to open file %s: %s",
- filename, strerror(errno));
- return -1;
- }
-
+ lseek(cli->fd, cli->chunk_offset, SEEK_SET);
header_len = trailer - cli->buf;
payload = cli->buf + header_len;
payload_len = cli->buf_len - header_len;
@@ -247,6 +244,50 @@ static int tip_client_get_payload(struct tip_client *cli)
return 1;
}
+static int tip_client_head_hdr(struct tip_client *cli)
+{
+ char *ptr;
+
+ ptr = strstr(cli->buf, "\r\n\r\n");
+ if (!ptr)
+ return 0;
+
+ if (!strncmp(cli->buf, "HTTP/1.1 404 Not Found", strlen("HTTP/1.1 404 Not Found"))) {
+ syslog(LOG_ERR, "server says file `%s' not found\n", filename);
+ return -1;
+ }
+
+ ptr = strstr(cli->buf, "Content-Length: ");
+ if (!ptr)
+ return -1;
+
+ if (sscanf(ptr, "Content-Length: %lu[^\r\n]", &cli->content_len) != 1)
+ return -1;
+ if (cli->content_len < 0)
+ return -1;
+ if (cli->content_len == 0) {
+ syslog(LOG_ERR, "server reports zero size file %s", filename);
+ return -1;
+ }
+
+ cli->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (cli->fd < 0) {
+ syslog(LOG_ERR, "failed to open file %s: %s",
+ filename, strerror(errno));
+ return -1;
+ }
+
+ if (posix_fallocate(cli->fd, 0, cli->content_len) < 0) {
+ syslog(LOG_ERR, "failed to allocate room for file %s: %s",
+ filename, strerror(errno));
+ return -1;
+ }
+
+ cli->state = TIP_CLIENT_DONE;
+
+ return 1;
+}
+
static int tip_client_post_redirect(struct tip_client *cli)
{
char *ptr;
@@ -310,6 +351,13 @@ static void tip_client_read_cb(struct ev_loop *loop, struct ev_io *io, int event
if (ret == 0)
goto close;
break;
+ case TIP_CLIENT_HEAD_HEADER:
+ ret = tip_client_head_hdr(cli);
+ if (ret < 0)
+ goto error;
+ if (!ret)
+ return;
+ goto close;
case TIP_CLIENT_POST_REDIRECT:
ret = tip_client_post_redirect(cli);
if (ret < 0)
@@ -348,12 +396,23 @@ static void tip_client_connect_cb(struct ev_loop *loop, struct ev_io *io, int ev
return;
}
- syslog(LOG_INFO, "connected to %s to fetch file %s\n", addr, filename);
-
- if (cli->state == TIP_CLIENT_POST_REDIRECT)
- snprintf(buf, sizeof(buf), "POST /%s HTTP/1.1\r\n\r\n", filename);
- else
+ switch (cli->state) {
+ case TIP_CLIENT_GET_HEADER:
+ syslog(LOG_INFO, "connected to %s to fetch file %s\n",
+ inet_ntoa(cli->addr.sin_addr), filename);
snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\n\r\n", filename);
+ break;
+ case TIP_CLIENT_HEAD_HEADER:
+ syslog(LOG_INFO, "connected to %s to get file size of %s\n",
+ inet_ntoa(cli->addr.sin_addr), filename);
+ snprintf(buf, sizeof(buf), "HEAD /%s HTTP/1.1\r\n\r\n", filename);
+ break;
+ case TIP_CLIENT_POST_REDIRECT:
+ syslog(LOG_INFO, "connected to %s to report redirection for %s\n",
+ inet_ntoa(cli->addr.sin_addr), filename);
+ snprintf(buf, sizeof(buf), "POST /%s HTTP/1.1\r\n\r\n", filename);
+ break;
+ }
ret = send(cli->io.fd, buf, strlen(buf), 0);
if (ret < 0) {
@@ -472,9 +531,10 @@ static char _filename[PATH_MAX + 1];
int main(int argc, char *argv[])
{
struct timeval tv_start, tv_stop, tv;
+ uint64_t data_len = 0, file_size = 0;
bool file_chunk[MAX_CHUNKS] = {};
- uint64_t data_len = 0;
- int i, k;
+ uint64_t chunk_size;
+ int i, k, fd;
if (argc != 3) {
printf("%s [ip] [file]\n", argv[0]);
@@ -490,12 +550,26 @@ int main(int argc, char *argv[])
gettimeofday(&tv_start, NULL);
+ do {
+ filename = argv[2];
+ _cli.state = TIP_CLIENT_HEAD_HEADER;
+ } while (tip_client_request_file(&_cli, addr, filename) > 0);
+
+ if (_cli.state != TIP_CLIENT_DONE)
+ goto err;
+
+ fd = _cli.fd;
+ file_size = _cli.content_len;
+
for (i = 0; i < MAX_CHUNKS; i++) {
memset(&_cli, 0, sizeof(_cli));
k = select_file_chunk(file_chunk);
snprintf(_filename, sizeof(_filename), "%s.%u", argv[2], k);
filename = _filename;
+ chunk_size = file_size / MAX_CHUNKS;
+ _cli.chunk_offset = chunk_size * k;
+ _cli.fd = fd;
do {
syslog(LOG_INFO, "Requesting file %s to server\n", filename);
@@ -507,7 +581,7 @@ int main(int argc, char *argv[])
file_chunk[k] = true;
data_len += _cli.data_len;
}
-
+err:
gettimeofday(&tv_stop, NULL);
timersub(&tv_stop, &tv_start, &tv);