runtime split original file into chunks

No need to split the original file on the server side.
master
tiptorrent development team 2021-09-23 22:05:20 +02:00
parent e39f7f8e3c
commit 324fdcfd58
3 changed files with 74 additions and 5 deletions

View File

@ -471,6 +471,7 @@ void tip_server_accept_cb(struct ev_loop *loop, struct ev_io *io, int events)
}
memcpy(&cli->addr, &client_addr, sizeof(client_addr));
cli->fd = -1;
cli->chunk = -1;
syslog(LOG_ERR, "accepting client connection from %s:%hu",
inet_ntoa(cli->addr.sin_addr), htons(cli->addr.sin_port));

View File

@ -6,6 +6,8 @@
#include <stdbool.h>
#include <netinet/in.h>
#define MAX_CHUNKS 4
#define TIP_MSG_REQUEST_MAXLEN 131072
extern const char *root;
@ -48,7 +50,9 @@ struct tip_client {
enum tip_http_method method;
const char *uri;
const char *path;
uint32_t chunk;
off_t size;
off_t left;
int fd;
off_t offset;

View File

@ -59,6 +59,7 @@ int tip_client_state_process_payload(struct tip_client *cli)
char _uri[32], *uri = _uri;
char allow_redirect_str[5];
char path[PATH_MAX + 1];
char *chunk = NULL;
struct stat st;
int err;
@ -93,14 +94,37 @@ int tip_client_state_process_payload(struct tip_client *cli)
if (!sanitize(uri))
return tip_client_method_not_found(cli);
/* skip initial / */
uri++;
switch (cli->method) {
case TIP_METHOD_GET:
case TIP_METHOD_POST:
/* get chunk number from file extension, e.g. FILE.0 */
chunk = strchr(uri, '.');
if (chunk) {
*chunk = '\0';
chunk++;
cli->chunk = atoi(chunk);
if (cli->chunk >= MAX_CHUNKS)
return tip_client_file_not_found(cli);
}
break;
case TIP_METHOD_HEAD:
break;
}
snprintf(path, PATH_MAX, "%s/%s", root, uri);
err = stat(path, &st);
if (err < 0)
return tip_client_file_not_found(cli);
/* skip initial / */
uri++;
/* restore the original uri that was mangled. */
if (chunk) {
chunk--;
*chunk = '.';
}
cli->uri = strdup(uri);
cli->path = strdup(path);
@ -139,6 +163,8 @@ int tip_client_state_process_payload(struct tip_client *cli)
int tip_client_state_process_payload_reply(struct tip_client *cli)
{
uint64_t chunk_size;
off_t chunk_offset;
char buf[1024];
int fd;
@ -156,8 +182,35 @@ int tip_client_state_process_payload_reply(struct tip_client *cli)
if (fd < 0)
return tip_client_file_not_found(cli);
if (cli->method == TIP_METHOD_POST)
switch (cli->method) {
case TIP_METHOD_GET:
if (cli->chunk < 0)
break;
chunk_size = cli->size / MAX_CHUNKS;
if (cli->size % MAX_CHUNKS) {
if (cli->chunk < MAX_CHUNKS - 1) {
chunk_size++;
chunk_offset = chunk_size * cli->chunk;
} else {
chunk_offset = chunk_size * cli->chunk;
chunk_offset += MAX_CHUNKS - 1;
chunk_size--;
}
} else {
chunk_offset = chunk_size * cli->chunk;
}
cli->size = chunk_size;
cli->offset = chunk_offset;
break;
case TIP_METHOD_POST:
cli->size = 0;
break;
case TIP_METHOD_HEAD:
break;
}
cli->left = cli->size;
snprintf(buf, sizeof(buf),
"HTTP/1.1 200 OK\r\nContent-Length: %lu\r\n\r\n",
@ -181,10 +234,21 @@ int tip_client_state_process_payload_reply(struct tip_client *cli)
int tip_client_state_process_payload_bulk(struct tip_client *cli)
{
if (sendfile(tip_client_socket(cli), cli->fd, &cli->offset, BLOCK) < 0)
uint32_t bytes;
int ret;
if (cli->left < BLOCK)
bytes = cli->left;
else
bytes = BLOCK;
ret = sendfile(tip_client_socket(cli), cli->fd, &cli->offset, bytes);
if (ret < 0)
return -1;
if (cli->offset >= cli->size) {
cli->left -= ret;
if (cli->left <= 0) {
cli->state = TIP_CLIENT_CLOSE_WAIT;
return 1;
}