Improve FTP throughput

This commit is contained in:
Michael Theall 2016-01-12 16:24:01 -06:00
parent d70cc5a238
commit 1c5084e08e
4 changed files with 104 additions and 43 deletions

View File

@ -33,7 +33,7 @@ DATA := data
INCLUDES := include INCLUDES := include
APP_TITLE := ftBRONY APP_TITLE := ftBRONY
APP_DESCRIPTION := Like ftPONY but magical. APP_DESCRIPTION := ftBRONY v1.2
APP_AUTHOR := mtheall APP_AUTHOR := mtheall
ICON := ftbrony.png ICON := ftbrony.png
@ -44,7 +44,7 @@ ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O3 -mword-relocations \ CFLAGS := -g -Wall -O3 -mword-relocations \
$(ARCH) \ $(ARCH) \
-DSTATUS_STRING="\"ftbrony v1.1\"" -DSTATUS_STRING="\"ftbrony v1.2\""
CFLAGS += $(INCLUDE) -DARM11 -D_3DS CFLAGS += $(INCLUDE) -DARM11 -D_3DS

View File

@ -3,7 +3,7 @@ TARGET := $(notdir $(CURDIR))
CFILES := $(wildcard source/*.c) CFILES := $(wildcard source/*.c)
OFILES := $(patsubst source/%,build.linux/%,$(CFILES:.c=.o)) OFILES := $(patsubst source/%,build.linux/%,$(CFILES:.c=.o))
CFLAGS := -g -Wall -Iinclude -DSTATUS_STRING="\"ftpd v1.0\"" CFLAGS := -g -Wall -Iinclude -DSTATUS_STRING="\"ftpd v1.2\""
LDFLAGS := LDFLAGS :=
.PHONY: all clean .PHONY: all clean

View File

@ -22,10 +22,12 @@
#define POLL_UNKNOWN (~(POLLIN|POLLOUT)) #define POLL_UNKNOWN (~(POLLIN|POLLOUT))
#define XFER_BUFFERSIZE 4096 #define XFER_BUFFERSIZE 32768
#define SOCK_BUFFERSIZE 32768
#define FILE_BUFFERSIZE 65536
#define CMD_BUFFERSIZE 1024 #define CMD_BUFFERSIZE 1024
#define SOC_ALIGN 0x1000 #define SOCU_ALIGN 0x1000
#define SOC_BUFFERSIZE 0x100000 #define SOCU_BUFFERSIZE 0x100000
#define LISTEN_PORT 5000 #define LISTEN_PORT 5000
#ifdef _3DS #ifdef _3DS
#define DATA_PORT (LISTEN_PORT+1) #define DATA_PORT (LISTEN_PORT+1)
@ -101,6 +103,8 @@ struct ftp_session_t
int (*transfer)(ftp_session_t*); /*! data transfer callback */ int (*transfer)(ftp_session_t*); /*! data transfer callback */
char buffer[XFER_BUFFERSIZE]; /*! persistent data between callbacks */ char buffer[XFER_BUFFERSIZE]; /*! persistent data between callbacks */
char tmp_buffer[XFER_BUFFERSIZE]; /*! persistent data between callbacks */
char file_buffer[FILE_BUFFERSIZE]; /*! stdio file buffer */
size_t bufferpos; /*! persistent buffer position between callbacks */ size_t bufferpos; /*! persistent buffer position between callbacks */
size_t buffersize; /*! persistent buffer size between callbacks */ size_t buffersize; /*! persistent buffer size between callbacks */
uint64_t filepos; /*! persistent file position between callbacks */ uint64_t filepos; /*! persistent file position between callbacks */
@ -108,7 +112,7 @@ struct ftp_session_t
union union
{ {
DIR *dp; /*! persistent open directory pointer between callbacks */ DIR *dp; /*! persistent open directory pointer between callbacks */
int fd; /*! persistent open file descriptor between callbacks */ FILE *fp; /*! persistent open file pointer between callbacks */
}; };
}; };
@ -181,17 +185,21 @@ ftp_command_cmp(const void *p1,
#ifdef _3DS #ifdef _3DS
/*! SOC service buffer */ /*! SOC service buffer */
static u32 *SOC_buffer = NULL; static u32 *SOCU_buffer = NULL;
#endif #endif
/*! server listen address */ /*! server listen address */
static struct sockaddr_in serv_addr; static struct sockaddr_in serv_addr;
/*! listen file descriptor */ /*! listen file descriptor */
static int listenfd = -1; static int listenfd = -1;
#ifdef _3DS
/*! current data port */ /*! current data port */
static in_port_t data_port = DATA_PORT; static in_port_t data_port = DATA_PORT;
#endif
/*! list of ftp sessions */ /*! list of ftp sessions */
static ftp_session_t *sessions = NULL; static ftp_session_t *sessions = NULL;
/*! socket buffersize */
static int sock_buffersize = SOCK_BUFFERSIZE;
/*! Allocate a new data port /*! Allocate a new data port
* *
@ -237,6 +245,32 @@ ftp_set_socket_nonblocking(int fd)
return 0; return 0;
} }
/*! set socket options
*
* @param[in] fd socket
*/
static void
ftp_set_socket_options(int fd)
{
int rc;
/* it's okay if this fails */
rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
&sock_buffersize, sizeof(sock_buffersize));
if(rc != 0)
{
console_print(RED "setsockopt: %d %s\n" RESET, errno, strerror(errno));
}
/* it's okay if this fails */
rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
&sock_buffersize, sizeof(sock_buffersize));
if(rc != 0)
{
console_print(RED "setsockopt: %d %s\n" RESET, errno, strerror(errno));
}
}
/*! close a socket /*! close a socket
* *
* @param[in] fd socket to close * @param[in] fd socket to close
@ -325,10 +359,10 @@ ftp_session_close_file(ftp_session_t *session)
{ {
int rc; int rc;
rc = close(session->fd); rc = fclose(session->fp);
if(rc != 0) if(rc != 0)
console_print(RED "close: %d %s\n" RESET, errno, strerror(errno)); console_print(RED "fclose: %d %s\n" RESET, errno, strerror(errno));
session->fd = -1; session->fp = NULL;
} }
/*! open file for reading for ftp session /*! open file for reading for ftp session
@ -344,15 +378,23 @@ ftp_session_open_file_read(ftp_session_t *session)
struct stat st; struct stat st;
/* open file in read mode */ /* open file in read mode */
session->fd = open(session->buffer, O_RDONLY); session->fp = fopen(session->buffer, "rb");
if(session->fd < 0) if(session->fp == NULL)
{ {
console_print(RED "open '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno)); console_print(RED "fopen '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno));
return -1; return -1;
} }
/* it's okay if this fails */
errno = 0;
rc = setvbuf(session->fp, session->file_buffer, _IOFBF, FILE_BUFFERSIZE);
if(rc != 0)
{
console_print(RED "setvbuf: %d %s\n" RESET, errno, strerror(errno));
}
/* get the file size */ /* get the file size */
rc = fstat(session->fd, &st); rc = fstat(fileno(session->fp), &st);
if(rc != 0) if(rc != 0)
{ {
console_print(RED "fstat '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno)); console_print(RED "fstat '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno));
@ -380,10 +422,10 @@ ftp_session_read_file(ftp_session_t *session)
ssize_t rc; ssize_t rc;
/* read file at current position */ /* read file at current position */
rc = read(session->fd, session->buffer, sizeof(session->buffer)); rc = fread(session->buffer, 1, sizeof(session->buffer), session->fp);
if(rc < 0) if(rc < 0)
{ {
console_print(RED "read: %d %s\n" RESET, errno, strerror(errno)); console_print(RED "fread: %d %s\n" RESET, errno, strerror(errno));
return -1; return -1;
} }
@ -404,14 +446,24 @@ ftp_session_read_file(ftp_session_t *session)
static int static int
ftp_session_open_file_write(ftp_session_t *session) ftp_session_open_file_write(ftp_session_t *session)
{ {
int rc;
/* open file in write and create mode with truncation */ /* open file in write and create mode with truncation */
session->fd = open(session->buffer, O_WRONLY|O_CREAT|O_TRUNC, 0644); session->fp = fopen(session->buffer, "wb");
if(session->fd < 0) if(session->fp == NULL)
{ {
console_print(RED "open '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno)); console_print(RED "fopen '%s': %d %s\n" RESET, session->buffer, errno, strerror(errno));
return -1; return -1;
} }
/* it's okay if this fails */
errno = 0;
rc = setvbuf(session->fp, session->file_buffer, _IOFBF, FILE_BUFFERSIZE);
if(rc != 0)
{
console_print(RED "setvbuf: %d %s\n" RESET, errno, strerror(errno));
}
/* reset file position */ /* reset file position */
/* TODO: support REST command */ /* TODO: support REST command */
session->filepos = 0; session->filepos = 0;
@ -431,15 +483,16 @@ ftp_session_write_file(ftp_session_t *session)
ssize_t rc; ssize_t rc;
/* write to file at current position */ /* write to file at current position */
rc = write(session->fd, session->buffer + session->bufferpos, rc = fwrite(session->buffer + session->bufferpos,
session->buffersize - session->bufferpos); 1, session->buffersize - session->bufferpos,
session->fp);
if(rc < 0) if(rc < 0)
{ {
console_print(RED "write: %d %s\n" RESET, errno, strerror(errno)); console_print(RED "fwrite: %d %s\n" RESET, errno, strerror(errno));
return -1; return -1;
} }
else if(rc == 0) else if(rc == 0)
console_print(RED "write: wrote 0 bytes\n" RESET); console_print(RED "fwrite: wrote 0 bytes\n" RESET);
/* adjust file position */ /* adjust file position */
session->filepos += rc; session->filepos += rc;
@ -766,6 +819,9 @@ ftp_session_connect(ftp_session_t *session)
return -1; return -1;
} }
/* set socket options */
ftp_set_socket_options(session->data_fd);
/* connect to peer */ /* connect to peer */
rc = connect(session->data_fd, (struct sockaddr*)&session->peer_addr, rc = connect(session->data_fd, (struct sockaddr*)&session->peer_addr,
sizeof(session->peer_addr)); sizeof(session->peer_addr));
@ -986,18 +1042,18 @@ ftp_init(void)
#endif #endif
/* allocate buffer for SOC service */ /* allocate buffer for SOC service */
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE); SOCU_buffer = (u32*)memalign(SOCU_ALIGN, SOCU_BUFFERSIZE);
if(SOC_buffer == NULL) if(SOCU_buffer == NULL)
{ {
console_print(RED "memalign: failed to allocate\n" RESET); console_print(RED "memalign: failed to allocate\n" RESET);
goto memalign_fail; goto memalign_fail;
} }
/* initialize SOC service */ /* initialize SOC service */
ret = socInit(SOC_buffer, SOC_BUFFERSIZE); ret = socInit(SOCU_buffer, SOCU_BUFFERSIZE);
if(ret != 0) if(ret != 0)
{ {
console_print(RED "SOC_Initialize: 0x%08X\n" RESET, (unsigned int)ret); console_print(RED "socInit: 0x%08X\n" RESET, (unsigned int)ret);
goto soc_fail; goto soc_fail;
} }
#endif #endif
@ -1011,6 +1067,9 @@ ftp_init(void)
return -1; return -1;
} }
/* set socket options */
ftp_set_socket_options(listenfd);
/* get address to listen on */ /* get address to listen on */
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
#ifdef _3DS #ifdef _3DS
@ -1019,6 +1078,7 @@ ftp_init(void)
#else #else
serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(LISTEN_PORT); serv_addr.sin_port = htons(LISTEN_PORT);
#endif
/* reuse address */ /* reuse address */
{ {
@ -1031,7 +1091,6 @@ ftp_init(void)
return -1; return -1;
} }
} }
#endif
/* bind socket to listen address */ /* bind socket to listen address */
rc = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); rc = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
@ -1092,7 +1151,7 @@ ftp_init(void)
#ifdef _3DS #ifdef _3DS
soc_fail: soc_fail:
free(SOC_buffer); free(SOCU_buffer);
memalign_fail: memalign_fail:
#ifdef ENABLE_LOGGING #ifdef ENABLE_LOGGING
@ -1127,8 +1186,8 @@ ftp_exit(void)
/* deinitialize SOC service */ /* deinitialize SOC service */
ret = socExit(); ret = socExit();
if(ret != 0) if(ret != 0)
console_print(RED "SOC_Shutdown: 0x%08X\n" RESET, (unsigned int)ret); console_print(RED "socExit: 0x%08X\n" RESET, (unsigned int)ret);
free(SOC_buffer); free(SOCU_buffer);
#ifdef ENABLE_LOGGING #ifdef ENABLE_LOGGING
/* close log file */ /* close log file */
@ -1671,6 +1730,8 @@ FTP_DECLARE(PASV)
return ftp_send_response(session, 451, "\r\n"); return ftp_send_response(session, 451, "\r\n");
} }
ftp_set_socket_options(session->pasv_fd);
session->pasv_addr.sin_port = htons(next_data_port()); session->pasv_addr.sin_port = htons(next_data_port());
#ifdef _3DS #ifdef _3DS
@ -1947,7 +2008,6 @@ FTP_DECLARE(RNFR)
FTP_DECLARE(RNTO) FTP_DECLARE(RNTO)
{ {
int rc; int rc;
char buffer[XFER_BUFFERSIZE];
console_print(CYAN "%s %s\n" RESET, __func__, args ? args : ""); console_print(CYAN "%s %s\n" RESET, __func__, args ? args : "");
@ -1958,12 +2018,12 @@ FTP_DECLARE(RNTO)
session->flags &= ~SESSION_RENAME; session->flags &= ~SESSION_RENAME;
memcpy(buffer, session->buffer, XFER_BUFFERSIZE); memcpy(session->tmp_buffer, session->buffer, XFER_BUFFERSIZE);
if(build_path(session, args) != 0) if(build_path(session, args) != 0)
return ftp_send_response(session, 554, "%s\r\n", strerror(errno)); return ftp_send_response(session, 554, "%s\r\n", strerror(errno));
rc = rename(buffer, session->buffer); rc = rename(session->tmp_buffer, session->buffer);
if(rc != 0) if(rc != 0)
{ {
console_print(RED "rename: %d %s\n" RESET, errno, strerror(errno)); console_print(RED "rename: %d %s\n" RESET, errno, strerror(errno));

View File

@ -65,6 +65,7 @@ main(int argc,
/* initialize needed 3DS services */ /* initialize needed 3DS services */
gfxInitDefault(); gfxInitDefault();
gfxSet3D(false); gfxSet3D(false);
sdmcWriteSafe(false);
#endif #endif
/* initialize console subsystem */ /* initialize console subsystem */