I've also modified the code in FTPd_task() as follows. This fixes the first problem I was seeing where the build up of "Ground" sockets happens when I connect/disconnect from the FTP rapidly and fade Wi-Fi out. The changes from my last post of this code are:
/*TASK*-----------------------------------------------------------------
*
* Function Name : FTPd_task
* Returned Value : none
* Comments : FTP server.
*
*END*-----------------------------------------------------------------*/
void FTPd_task(pointer init_ptr, pointer creator)
{ /* Body */
FTPd_CONTEXT ftpd_context = { 0 };
sockaddr_in laddr;
uint_32 sock, childsock, listensock;
uint_32 error=RTCS_OK;
uint_16 remote_addr_len;
sockaddr_in remote_addr = {0};
#if FTPDCFG_ENABLE_MULTIPLE_CLIENTS
TASK_TEMPLATE_STRUCT_PTR t_ptr;
#endif
FTPd_SESSION_PTR session_ptr;
uint_32 option;
boolean dev_in_path = FALSE;
int_16 devlen = 0, rootdirlen = 0;
uint_32 parameter;
FTPd_task_id = RTCS_task_getid();
#ifdef __MQX__
/* Set up exit handler and context so that we can clean up if the FTP Server is terminated */
_task_set_environment( _task_get_id(), (pointer) &ftpd_context );
_task_set_exit_handler( _task_get_id(), FTPd_Exit_handler );
#endif
laddr.sin_family = AF_INET;
laddr.sin_port = IPPORT_FTP;
laddr.sin_addr.s_addr = INADDR_ANY;
// Create new listening socket
ftpd_context.LISTENSOCK = socket(PF_INET, SOCK_STREAM, 0);
listensock = ftpd_context.LISTENSOCK;
if (listensock == RTCS_SOCKET_ERROR)
{
error = RTCSERR_OUT_OF_SOCKETS;
}
// When the socket is bound, RTCS allocates a send buffer of the specified number of bytes, which controls how much sent data RTCS
// can buffer for the socket.
//Recommended to be a multiple of the maximum segment size (536), where the multiple is at least three.
if (!error)
{
option = FTPDCFG_BUFFER_SIZE;
error = setsockopt(listensock, SOL_TCP, OPT_TBSIZE, &option, sizeof(option));
}
// When the socket is bound, RTCS allocates a receive buffer of the specified number of bytes, which controls
// how much received data RTCS can buffer for the socket.
//Recommended to be a multiple of the maximum segment size (536), where the multiple is at least three.
if (!error)
{
option = FTPDCFG_BUFFER_SIZE;
error = setsockopt(listensock, SOL_TCP, OPT_RBSIZE, &option, sizeof(option));
}
// Zero: RTCS waits indefinitely for outgoing data during a call to send().
// Non-zero: RTCS waits for this number of milliseconds for incoming data during a call to send().
if (!error)
{
option = FTPDCFG_SEND_TIMEOUT;
error = setsockopt(listensock, SOL_TCP, OPT_SEND_TIMEOUT, &option, sizeof(option));
}
// RTCS maintains the connection for this number of milliseconds. Must be minimum of 180,000
if (!error)
{
option = FTPDCFG_CONNECT_TIMEOUT;
error = setsockopt(listensock, SOL_TCP, OPT_CONNECT_TIMEOUT, &option, sizeof(option));
}
// Two times the maximum segment lifetime (which is a constant). Returned information is for the last
// frame that the socket received.
if (!error)
{
option = FTPDCFG_TIMEWAIT_TIMEOUT;
error = setsockopt(listensock, SOL_TCP, OPT_TIMEWAIT_TIMEOUT, &option, sizeof(option));
}
// fixme cwp - added to see if we can fix ftp lockup on loss of wifi
if (!error)
{
option = FTPDCFG_RECEIVE_TIMEOUT; // Set this value to what you need (360000 for 6 minute, for me)
error = setsockopt(listensock, SOL_TCP, OPT_RECEIVE_TIMEOUT, &option, sizeof(option));
}
if (!error)
{
option = FTPDCFG_NO_NAGLE_ALGORITHM;
error = setsockopt(listensock, SOL_TCP, OPT_NO_NAGLE_ALGORITHM, &option, sizeof(option));
}
// Bind the new socket to local address
if (!error)
{
error = bind(listensock, (const sockaddr *)&laddr, sizeof(laddr));
}
// Start listening for incoming connection
if (!error)
{
error = listen(listensock, 0);
}
// Stop here if something went wrong setting up the listening socket (this shouldn't happen normally)
if (error)
{
RTCS_task_exit(creator, error);
}
// Resume the creator task (in this case it's falcon.c calling Falcon_initialize_networking(), which starts FTP and Telnet.
RTCS_task_resume_creator(creator, RTCS_OK);
for (;;)
{
remote_addr_len = sizeof(remote_addr);
// Check to see if there is any activity on the listening socket. If there is listensock will be returned, else 0
sock = RTCS_selectset(&listensock, 1, FTPDCFG_CONNECT_TIMEOUT);
if(sock != 0)
{
// There was activity on the listening socket, so accept the control socket connection
childsock = accept(sock,(sockaddr *)&remote_addr, &remote_addr_len);
if ((childsock != 0) && (childsock!=RTCS_SOCKET_ERROR))
{
// The connection was accepted successfully, so configure the FTP server
session_ptr = (FTPd_SESSION_PTR) RTCS_mem_alloc_zero(sizeof (FTPd_SESSION_STRUCT));
if ( session_ptr )
{
_mem_set_type(session_ptr, MEM_TYPE_FTPd_SESSION_PTR);
session_ptr->DATA_BUFFER_SIZE = FTPDCFG_BUFFER_SIZE; // KDC: Changed this
session_ptr->DATA_BUFFER_PTR = RTCS_mem_alloc_zero(session_ptr->DATA_BUFFER_SIZE);
if (session_ptr->DATA_BUFFER_PTR == NULL)
{
_mem_free(session_ptr);
session_ptr = NULL;
}
else
{
_mem_set_type(session_ptr->DATA_BUFFER_PTR, MEM_TYPE_FTPd_DATA_BUFFER);
}
}
if (session_ptr == NULL)
{
shutdown((uint_32)childsock, FTPDCFG_SHUTDOWN_OPTION);
}
else
{
session_ptr->CONTROL_SOCK = (uint_32) childsock;
session_ptr->CONNECTED = TRUE;
/* set default data ports */
session_ptr->SERVER_DATA_SOCKADDR.sin_family = AF_INET;
session_ptr->SERVER_DATA_SOCKADDR.sin_port = IPPORT_FTPDATA;
session_ptr->SERVER_DATA_SOCKADDR.sin_addr.s_addr = INADDR_ANY;
session_ptr->USER_DATA_SOCKADDR.sin_family = remote_addr.sin_family;
session_ptr->USER_DATA_SOCKADDR.sin_port = remote_addr.sin_port;
session_ptr->USER_DATA_SOCKADDR.sin_addr.s_addr = remote_addr.sin_addr.s_addr;
#if FTPDCFG_USES_MFS
//initialize current directory and current filesystem
devlen = _io_get_dev_for_path(session_ptr->CURRENT_FS_NAME, &dev_in_path, FTPD_DEVLEN,(char *)FTPd_rootdir, NULL);
session_ptr->CURRENT_FS = _io_get_fs_by_name(session_ptr->CURRENT_FS_NAME);
error = ioctl(session_ptr->CURRENT_FS, IO_IOCTL_CHECK_DIR_EXIST,(pointer)FTPd_rootdir );
if (error)
{
#endif
session_ptr->CURRENT_FS = NULL;
session_ptr->CURRENT_FTP_DIR = NULL;
session_ptr->CURRENT_FS_DIR[0] = '\0';
#if FTPDCFG_USES_MFS
}
else
{
// set current fs dir (including root dir)
strcpy(session_ptr->CURRENT_FS_DIR,FTPd_rootdir+devlen);
rootdirlen = strlen(session_ptr->CURRENT_FS_DIR);
// set current FTP dir
session_ptr->CURRENT_FTP_DIR = session_ptr->CURRENT_FS_DIR + rootdirlen - 1;
//check if there is / at the end of root dir name
if(*(session_ptr->CURRENT_FTP_DIR) != '\\' && *(session_ptr->CURRENT_FTP_DIR) != '/')
{
session_ptr->CURRENT_FTP_DIR++;
}
session_ptr->CURRENT_FTP_DIR[0] = '\\';
session_ptr->CURRENT_FTP_DIR[1] = '\0';
}
#endif
#if FTPDCFG_ENABLE_MULTIPLE_CLIENTS
/* Create a task to look after it */
RTCS_detachsock(childsock);
t_ptr = _task_get_template_ptr(MQX_NULL_TASK_ID);
if (RTCS_task_create("FTPd_child", t_ptr->TASK_PRIORITY, t_ptr->TASK_STACKSIZE, FTPd_child, (pointer) session_ptr) != RTCS_OK )
{
RTCS_attachsock(childsock);
shutdown(childsock, FLAG_ABORT_CONNECTION);
_mem_free(session_ptr->DATA_BUFFER_PTR);
_mem_free(session_ptr);
}
#else
// The FTP server has been setup, so call FTPd_child(), which will start responding to commands from a client
FTPd_child((pointer) session_ptr,0);
#endif
}
}
else
{
// Accepting the socket failed, so call shutdown to free any memory that was allocated for it.
shutdown((uint_32)childsock, FLAG_ABORT_CONNECTION);
}
}
}
}