#include "streaming.h" #include "../platform/pal.h" #include #include #include #ifndef _WIN32 #include #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); }