summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortiptorrent development team <tiptorrent@soleta.eu>2021-12-23 16:27:06 +0100
committertiptorrent development team <tiptorrent@soleta.eu>2021-12-23 19:11:37 +0100
commit35f3191e4c5b3c7d0df425c7c8b82fea4df66b74 (patch)
tree0ea3b7ebc42e8a5c42c85af87015fb29e781b341 /src
parent4e2ba97629e0daf378b133f53b0b0d9ad25d155e (diff)
use fallocate() to store the chunks in the file
The client sends a HTTP HEAD request to the server to check that the file exists and to get the file size, then it calls open() to create the file and fallocate() to preallocate the bytes. The client calculates the offset based on the chunk number and it calls lseek().
Diffstat (limited to 'src')
-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);