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().master
parent
4e2ba97629
commit
35f3191e4c
104
src/main.c
104
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue