feat(transfer): stream single files and bases above the 256 MiB ceiling (#318)

This commit is contained in:
2026-09-24 01:25:12 +02:00
parent f7d5dda93b
commit c387beb182
21 changed files with 1758 additions and 193 deletions
+55 -14
View File
@@ -38,6 +38,27 @@ static atomic_ullong io_bytes_read = 0;
static unsigned long long global_bwlimit(void);
/* Runtime whole-file receive bound (see protocol.h). Resolved once; an
* override can only LOWER the ceiling, never raise it above the protocol
* constant, so the wire/security bound is unchanged. A parse failure or a
* non-positive value leaves the default in place. */
unsigned long long protocol_whole_file_receive_limit(void) {
static atomic_ullong cached = 0;
unsigned long long value = atomic_load_explicit(&cached, memory_order_relaxed);
if (value != 0)
return value;
value = MAX_RECEIVE_WHOLE_FILE_SIZE;
const char* env = getenv("FASTSYNC_MAX_WHOLE_FILE_SIZE");
if (env && env[0] != '\0') {
char* end = NULL;
unsigned long long parsed = strtoull(env, &end, 10);
if (end && *end == '\0' && parsed > 0 && parsed < value)
value = parsed;
}
atomic_store_explicit(&cached, value, memory_order_relaxed);
return value;
}
/* ------------------------------------------------------------------------- *
* Transport vtable implementations.
*
@@ -769,17 +790,11 @@ bool protocol_send_data(ProtocolSession* session, const Data* data) {
return true;
}
Data* protocol_receive_data_limited(ProtocolSession* session, unsigned long long maximum_size) {
Data* protocol_receive_data_alloc(ProtocolSession* session, unsigned long long size) {
if (!session)
return NULL;
unsigned long long size = 0;
if (!protocol_receive_n_data(session, &size, sizeof(unsigned long long)))
if (size > MAX_DATA_PAYLOAD_SIZE)
return NULL;
if (size > MAX_DATA_PAYLOAD_SIZE || size > maximum_size) {
log_message(LOG_LEVEL_ERROR, "Data size %llu exceeds maximum %llu", size,
(unsigned long long)MAX_DATA_PAYLOAD_SIZE);
return NULL;
}
if (size > SIZE_MAX)
return NULL;
size_t allocation_size = size == 0 ? 1 : (size_t)size;
@@ -794,12 +809,6 @@ Data* protocol_receive_data_limited(ProtocolSession* session, unsigned long long
protocol_release_memory_for_session(session, allocation_size);
return NULL;
}
if (!protocol_receive_n_data(session, data, (size_t)size)) {
free(data);
protocol_release_memory_for_session(session, allocation_size);
return NULL;
}
log_debug_message(LOG_DEBUG_PROTO, "Received %llu data", size);
Data* result = data_create(data, (size_t)size);
if (!result) {
protocol_release_memory_for_session(session, allocation_size);
@@ -810,6 +819,32 @@ Data* protocol_receive_data_limited(ProtocolSession* session, unsigned long long
return result;
}
Data* protocol_receive_data_body(ProtocolSession* session, unsigned long long size) {
Data* result = protocol_receive_data_alloc(session, size);
if (!result)
return NULL;
if (!protocol_receive_n_data(session, result->data, (size_t)size)) {
data_destroy(result);
return NULL;
}
log_debug_message(LOG_DEBUG_PROTO, "Received %llu data", size);
return result;
}
Data* protocol_receive_data_limited(ProtocolSession* session, unsigned long long maximum_size) {
if (!session)
return NULL;
unsigned long long size = 0;
if (!protocol_receive_n_data(session, &size, sizeof(unsigned long long)))
return NULL;
if (size > MAX_DATA_PAYLOAD_SIZE || size > maximum_size) {
log_message(LOG_LEVEL_ERROR, "Data size %llu exceeds maximum %llu", size,
(unsigned long long)MAX_DATA_PAYLOAD_SIZE);
return NULL;
}
return protocol_receive_data_body(session, size);
}
bool protocol_send_int(ProtocolSession* session, int data) {
if (!protocol_send_n_data(session, &data, sizeof(int)))
return false;
@@ -1114,6 +1149,12 @@ Data* receive_data(int fd) {
Data* receive_data_limited(int fd, unsigned long long maximum_size) {
return protocol_receive_data_limited(legacy_session(fd, -1), maximum_size);
}
Data* receive_data_body(int fd, unsigned long long size) {
return protocol_receive_data_body(legacy_session(fd, -1), size);
}
Data* receive_data_alloc(int fd, unsigned long long size) {
return protocol_receive_data_alloc(legacy_session(fd, -1), size);
}
bool send_int(int fd, int data) {
return protocol_send_int(legacy_session(-1, fd), data);
}