RETR: use sendfile() to transmit files for improved performance and reduced memory footprint

This commit is contained in:
John Törnblom committed 2026-01-10 16:17:36 +01:00
1 parent d4d0aede3e
commit c3afb40d36
7 files changed
+125 -8

No files matched your search

+1
View File
@@ -21,6 +21,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags)
CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I.
SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c
SOURCE += posix/main.c posix/cmd.c posix/self.c
SOURCE += io-linux.c
all: $(ELF)
+1
View File
@@ -30,6 +30,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags)
CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I.
SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c
SOURCE += orbis/main.c orbis/cmd.c orbis/self.c
SOURCE += io-freebsd.c
all: $(ELF)
+1
View File
@@ -30,6 +30,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags)
CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I.
SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c
SOURCE += prospero/main.c prospero/cmd.c prospero/self.c
SOURCE += io-freebsd.c
all: $(ELF)
+8 -8
View File
@@ -19,6 +19,7 @@ along with this program; see the file COPYING. If not, see
#include <fcntl.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
@@ -518,9 +519,6 @@ ftp_cmd_RETR_fd(ftp_env_t *env, int fd) {
if(fstat(fd, &st)) {
return ftp_perror(env);
}
if(lseek(fd, off, SEEK_SET) < 0) {
return ftp_perror(env);
}
if(ftp_active_printf(env, "150 Starting data transfer\r\n")) {
return -1;
@@ -530,16 +528,18 @@ ftp_cmd_RETR_fd(ftp_env_t *env, int fd) {
return ftp_perror(env);
}
if(io_ncopy(fd, env->data_fd, st.st_size - off)) {
err = ftp_perror(env);
ftp_data_close(env);
return err;
}
err = io_sendfile(fd, env->data_fd, off, st.st_size - off);
if(ftp_data_close(env)) {
return ftp_perror(env);
}
if(err) {
return ftp_perror(env);
}
env->data_offset = 0;
return ftp_active_printf(env, "226 Transfer completed\r\n");
}
+55
View File
@@ -0,0 +1,55 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include "io.h"
int
io_sendfile(int fd, int s, off_t offset, size_t n) {
off_t copied = 0;
off_t sbytes = 0;
size_t nbytes;
while (copied < n) {
nbytes = n - copied;
if(nbytes > IO_COPY_BUFSIZE) {
nbytes = IO_COPY_BUFSIZE;
}
if(sendfile(fd, s, offset, nbytes, 0, &sbytes, 0) < 0) {
if(errno == EINTR) {
continue;
}
return -1;
}
if(sbytes == 0) {
errno = EPIPE;
return -1;
}
copied += sbytes;
offset += sbytes;
}
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <sys/sendfile.h>
#include <sys/errno.h>
#include "io.h"
int
io_sendfile(int in_fd, int out_fd, off_t offset, size_t n) {
off_t copied = 0;
size_t count;
ssize_t r;
while (copied < n) {
count = n - copied;
if(count > IO_COPY_BUFSIZE) {
count = IO_COPY_BUFSIZE;
}
if((r=sendfile(out_fd, in_fd, &offset, count)) < 0) {
if(errno == EINTR) {
continue;
}
return -1;
}
if(r == 0) {
errno = EPIPE;
return -1;
}
copied += r;
}
return 0;
}
+6
View File
@@ -43,6 +43,12 @@ int io_nwrite(int fd, const void* buf, size_t n);
int io_ncopy(int fd_in, int fd_out, size_t n);
/**
* Copy exactly N bytes from a file descriptor to a socket.
**/
int io_sendfile(int fd, int sock, off_t off, size_t n);
/**
* Read exactly N bytes from the given file descriptor without affecting its
* position.