netutils/ftpc: implemented FTPC_OVER_SENDFILE option.

This option enables using sendfile() in ftpc binary transfer mode of PUT operation.
If the option is enabled but ASCII transfer mode is activated,
ftpc falls back to the combination of read() and write().
Using sendfile() provides a higher performance compared to
the combination of read() and write().

Also this option is useful for testing / debugging tcp_sendfile()
functionality of NuttX TCP/IP stack.
This commit is contained in:
Alexander Lunev 2022-01-18 18:40:32 +03:00 committed by Xiang Xiao
parent 371beb2a0f
commit b8c060260c
2 changed files with 70 additions and 10 deletions

View File

@ -50,4 +50,15 @@ config FTPC_DISABLE_EPSV
if you need to use PASV instead, use this option to disable EPSV and
fallback to using PASV.
config FTPC_OVER_SENDFILE
bool "Use sendfile() in ftpc binary transfer mode of PUT operation"
default y
depends on NET_SENDFILE
---help---
This option enables using sendfile() in ftpc binary transfer mode of PUT
operation. If the option is enabled but ASCII transfer mode is activated,
ftpc falls back to the combination of read() and write().
Using sendfile() provides a higher performance compared
to the combination of read() and write().
endif

View File

@ -25,6 +25,7 @@
#include "ftpc_config.h"
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@ -65,11 +66,60 @@
*
****************************************************************************/
#ifdef CONFIG_FTPC_OVER_SENDFILE
static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
FAR FILE *linstream, FILE *routstream)
FAR FILE *linstream)
{
struct stat stat_buf;
off_t offset = session->offset;
ssize_t result;
ssize_t len;
int linfd = fileno(linstream);
if (linfd == -1 || fstat(linfd, &stat_buf) == -1)
{
ftpc_xfrabort(session, NULL);
return ERROR;
}
/* Loop until the entire file is sent */
len = stat_buf.st_size - offset;
while (len > 0)
{
result = sendfile(session->data.sd, linfd, &offset, len);
if (result == -1 && errno == EAGAIN)
{
continue;
}
else if (result == -1)
{
ftpc_xfrabort(session, NULL);
return ERROR;
}
len -= result;
/* Increment the size of the file sent */
session->size += result;
}
/* Return success */
return OK;
}
#else
static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
FAR FILE *linstream)
{
ssize_t nread;
ssize_t nwritten;
FILE *routstream = session->data.outstream;
/* Loop until the entire file is sent */
@ -111,6 +161,7 @@ static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
session->size += nread;
}
}
#endif
/****************************************************************************
* Name: ftpc_sendtext
@ -121,10 +172,11 @@ static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
****************************************************************************/
static int ftpc_sendtext(FAR struct ftpc_session_s *session,
FAR FILE *linstream, FAR FILE *routstream)
FAR FILE *linstream)
{
int ch;
int ret = OK;
FILE *routstream = session->data.outstream;
/* Write characters one at a time. */
@ -174,7 +226,6 @@ static int ftpc_sendtext(FAR struct ftpc_session_s *session,
static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
FILE *stream, uint8_t how, uint8_t xfrmode)
{
long offset = session->offset;
#ifdef CONFIG_DEBUG_FEATURES
FAR char *rname;
FAR char *str;
@ -182,8 +233,6 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
#endif
int ret;
session->offset = 0;
/* Were we asked to store a file uniquely? Does the host support the STOU
* command?
*/
@ -212,10 +261,10 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
* allow REST immediately before STOR for binary files.
*/
if (offset > 0)
if (session->offset > 0)
{
ret = ftpc_cmd(session, "REST %ld", offset);
session->size = offset;
ret = ftpc_cmd(session, "REST %ld", session->offset);
session->size = session->offset;
}
/* Send the file using STOR, STOU, or APPE:
@ -331,11 +380,11 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
if (xfrmode == FTPC_XFRMODE_ASCII)
{
ret = ftpc_sendtext(session, stream, session->data.outstream);
ret = ftpc_sendtext(session, stream);
}
else
{
ret = ftpc_sendbinary(session, stream, session->data.outstream);
ret = ftpc_sendbinary(session, stream);
}
ftpc_sockflush(&session->data);