diff options
author | tiptorrent development team <tiptorrent@soleta.eu> | 2021-12-23 16:27:06 +0100 |
---|---|---|
committer | tiptorrent development team <tiptorrent@soleta.eu> | 2021-12-23 19:11:37 +0100 |
commit | 35f3191e4c5b3c7d0df425c7c8b82fea4df66b74 (patch) | |
tree | 0ea3b7ebc42e8a5c42c85af87015fb29e781b341 /src | |
parent | 4e2ba97629e0daf378b133f53b0b0d9ad25d155e (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.c | 104 |
1 files changed, 89 insertions, 15 deletions
@@ -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); |