|
#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);
|
|
}
|