#include "streaming.h"
#include "../platform/pal.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
void streaming_config_init(streaming_config_t *config) {
if (!config) return;
config->read_buffer_size = 32768;
config->write_buffer_size = 65536;
config->sendfile_threshold = 16384;
config->chunk_size = 8192;
config->max_memory_per_request = 10 * 1024 * 1024;
}
int streaming_send_all(socket_t fd, const char *data, size_t len) {
size_t sent = 0;
while (sent < len) {
ssize_t n = pal_socket_send(fd, data + sent, len - sent, 0);
if (n <= 0) {
return NWEDAV_ERROR;
}
sent += n;
}
return NWEDAV_OK;
}
int streaming_send_file(socket_t fd, int file_fd, off_t offset, size_t len, size_t buffer_size) {
if (buffer_size == 0) buffer_size = STREAMING_DEFAULT_BUFFER_SIZE;
#ifndef _WIN32
{
off_t off = offset;
size_t sf_remaining = len;
ssize_t sent = pal_sendfile(fd, file_fd, &off, sf_remaining);
if (sent > 0) {
sf_remaining -= sent;
while (sf_remaining > 0) {
sent = pal_sendfile(fd, file_fd, &off, sf_remaining);
if (sent <= 0) break;
sf_remaining -= sent;
}
if (sf_remaining == 0) {
return NWEDAV_OK;
}
}
if (lseek(file_fd, offset, SEEK_SET) < 0) {
return NWEDAV_ERROR;
}
}
#endif
char *buffer = malloc(buffer_size);
if (!buffer) return NWEDAV_ERROR;
size_t remaining = len;
int result = NWEDAV_OK;
while (remaining > 0) {
size_t to_read = remaining < buffer_size ? remaining : buffer_size;
#ifdef _WIN32
DWORD bytes_read;
if (!ReadFile((HANDLE)_get_osfhandle(file_fd), buffer, (DWORD)to_read, &bytes_read, NULL) || bytes_read == 0) {
result = NWEDAV_ERROR;
break;
}
ssize_t n = bytes_read;
#else
ssize_t n = read(file_fd, buffer, to_read);
if (n <= 0) {
result = NWEDAV_ERROR;
break;
}
#endif
if (streaming_send_all(fd, buffer, n) != NWEDAV_OK) {
result = NWEDAV_ERROR;
break;
}
remaining -= n;
}
free(buffer);
return result;
}
int streaming_send_file_range(socket_t fd, int file_fd, int64_t start, int64_t end, size_t buffer_size) {
#ifndef _WIN32
if (lseek(file_fd, start, SEEK_SET) < 0) {
return NWEDAV_ERROR;
}
#else
LARGE_INTEGER li;
li.QuadPart = start;
if (!SetFilePointerEx((HANDLE)_get_osfhandle(file_fd), li, NULL, FILE_BEGIN)) {
return NWEDAV_ERROR;
}
#endif
size_t len = (size_t)(end - start + 1);
return streaming_send_file(fd, file_fd, start, len, buffer_size);
}
int streaming_send_chunked_start(socket_t fd) {
(void)fd;
return NWEDAV_OK;
}
int streaming_send_chunk(socket_t fd, const char *data, size_t len) {
if (len == 0) return NWEDAV_OK;
char header[32];
int header_len = snprintf(header, sizeof(header), "%zx\r\n", len);
if (header_len <= 0) return NWEDAV_ERROR;
if (streaming_send_all(fd, header, header_len) != NWEDAV_OK) {
return NWEDAV_ERROR;
}
if (streaming_send_all(fd, data, len) != NWEDAV_OK) {
return NWEDAV_ERROR;
}
if (streaming_send_all(fd, "\r\n", 2) != NWEDAV_OK) {
return NWEDAV_ERROR;
}
return NWEDAV_OK;
}
int streaming_send_chunked_end(socket_t fd) {
return streaming_send_all(fd, "0\r\n\r\n", 5);
}