📄 ftpdlib.c
字号:
* sessions have exited.
*/
LOCAL void ftpdSessionDelete
(
FAST FTPD_SESSION_DATA *pSlot /* pointer to the slot to be deleted */
)
{
if (pSlot == NULL) /* null slot? don't do anything */
return;
/*
* The deletion of a session entry must be an atomic operation to support
* an upper limit on the number of simultaneous connections allowed.
* This mutual exclusion also prevents a race condition with the server
* shutdown routine. The last client session will always send an exit
* signal to the shutdown routine, whether or not the shutdown flag was
* detected during normal processing.
*/
semTake (ftpsMutexSem, WAIT_FOREVER);
--ftpdNumTasks;
--ftpsCurrentClients;
lstDelete (&ftpsSessionList, &pSlot->node);
ftpdSockFree (&pSlot->cmdSock); /* release data and command sockets */
ftpdSockFree (&pSlot->dataSock);
KHEAP_FREE((char *)pSlot);
/* Send required signal if all sessions are closed. */
if (ftpsShutdownFlag)
{
if (ftpsCurrentClients == 0)
semGive (ftpsSignalSem);
}
semGive (ftpsMutexSem);
return;
}
/*******************************************************************************
*
* ftpdWorkTask - main protocol processor for the FTP service
*
* This function handles all the FTP protocol requests by parsing
* the request string and performing appropriate actions and returning
* the result strings. The main body of this function is a large
* FOREVER loop which reads in FTP request commands from the client
* located on the other side of the connection. If the result of
* parsing the request indicates a valid command, ftpdWorkTask() will
* call appropriate functions to handle the request and return the
* result of the request. The parsing of the requests are done via
* a list of strncmp routines for simplicity.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* NOMANUAL
*
* INTERNAL
* To handle multiple simultaneous connections, this routine and all secondary
* routines which process client commands must be re-entrant. If the server's
* halt routine is started, the shutdown flag is set, causing this routine to
* exit after completing any operation already in progress.
*/
LOCAL STATUS ftpdWorkTask
(
FTPD_SESSION_DATA *pSlot /* pointer to the active slot to be handled */
)
{
FAST int sock; /* command socket descriptor */
FAST char *pBuf; /* pointer to session specific buffer */
struct sockaddr_in passiveAddr; /* socket address in passive mode */
FAST char *dirName; /* directory name place holder */
FAST int numRead;
int addrLen = sizeof (passiveAddr); /* for getpeername */
int portNum [6]; /* used for "%d,%d,%d,%d,%d,%d" */
u_long value;
char *pTail;
char newPath [MAX_FILENAME_LENGTH];
char curDirName [MAX_FILENAME_LENGTH];
char *pFileName;
FILE *inStream;
FILE *outStream;
char *upperCommand; /* convert command to uppercase */
pBuf = &pSlot->buf [0]; /* use session specific buffer area */
sock = pSlot->cmdSock;
if (ftpsShutdownFlag)
{
/* Server halt in progress - send abort message to client. */
ftpdCmdSend (pSlot, sock, 421,
"Service not available, closing control connection",
0, 0, 0, 0, 0, 0);
ftpdSessionDelete (pSlot);
return (OK);
}
/* tell the client we're ready to rock'n'roll */
#ifdef _WRS_VXWORKS_5_X
if (ftpdCmdSend (pSlot, sock, 220, messages [MSG_SERVER_READY],
(int)vxWorksVersion, 0, 0, 0, 0, 0) == ERROR)
#else
if (ftpdCmdSend (pSlot, sock, 220, messages [MSG_SERVER_READY],
(int)runtimeVersion, 0, 0, 0, 0, 0) == ERROR)
#endif /* _WRS_VXWORKS_5_X */
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
FOREVER
{
taskDelay (1); /* time share among same priority tasks */
/* Check error in writting to the control socket */
if (pSlot->cmdSockError == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
/*
* Stop processing client requests if a server halt is in progress.
* These tests of the shutdown flag are not protected with the
* mutual exclusion semaphore to prevent unnecessary synchronization
* between client sessions. Because the secondary tasks execute at
* a lower priority than the primary task, the worst case delay
* before ending this session after shutdown has started would only
* allow a single additional command to be performed.
*/
if (ftpsShutdownFlag)
break;
/* get a request command */
FOREVER
{
taskDelay (1); /* time share among same priority tasks */
if ((numRead = read (sock, pBuf, 1)) <= 0)
{
/*
* The primary server task will close the control connection
* when a halt is in progress, causing an error on the socket.
* In this case, ignore the error and exit the command loop
* to send a termination message to the connected client.
*/
if (ftpsShutdownFlag)
{
*pBuf = EOS;
break;
}
/*
* Send a final message if the control socket
* closed unexpectedly.
*/
if (numRead == 0)
ftpdCmdSend (pSlot, sock, 221, messages [MSG_NO_GOOD_BYE],
0, 0, 0, 0, 0, 0);
ftpdSessionDelete (pSlot);
return ERROR;
}
/* Skip the CR in the buffer. */
if ( *pBuf == '\r' )
continue;
/* End Of Command delimeter or exceed the buf boundry. exit loop and process command */
if ( *pBuf == '\n' ||
pBuf >= &pSlot->buf [BUFSIZE-1] )
{
*pBuf = EOS;
break;
}
pBuf++; /* Advance to next character to read */
}
/* Reset Buffer Pointer before we use it */
pBuf = &pSlot->buf [0];
/* convert the command to upper-case */
for (upperCommand = pBuf; (*upperCommand != ' ') &&
(*upperCommand != EOS); upperCommand++)
*upperCommand = toupper (*upperCommand);
ftpdDebugMsg ("read command %s\n", (int)pBuf,0,0,0);
/*
* Send an abort message to the client if a server
* shutdown was started while reading the next command.
*/
if (ftpsShutdownFlag)
{
ftpdCmdSend (pSlot, sock, 421,
"Service not available, closing control connection",
0, 0, 0, 0, 0, 0);
break;
}
if (strncmp (pBuf, "USER", 4) == 0)
{
/* check user name */
/* Actually copy the user name into a buffer and save it */
/* till the password comes in. Name is located one space */
/* character after USER string */
if ( *(pBuf + 4) == '\0' )
pSlot->user[0] = '\0'; /* NOP user for null user */
else
strncpy(pSlot->user, pBuf+5, MAX_LOGIN_NAME_LEN);
pSlot->status &= ~FTPD_USER_OK;
if (ftpdCmdSend (pSlot, sock, 331, messages [MSG_PASSWORD_REQUIRED],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
continue;
}
else if (strncmp (pBuf, "PASS", 4) == 0)
{
/* check user passwd */
/* Actually check it against earlier supplied user name */
if ( loginVerifyRtn != (FUNCPTR)NULL )
{
if ( (FUNCPTR *)(loginVerifyRtn)(pSlot->user, pBuf+5) != OK )
{
if (ftpdCmdSend (pSlot, sock,
530, messages [MSG_USER_LOGIN_FAILED],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
pSlot->status &= ~FTPD_USER_OK;
continue;
}
}
pSlot->status |= FTPD_USER_OK;
if (ftpdCmdSend (pSlot, sock, 230, messages [MSG_USER_LOGGED_IN],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
continue;
}
else if (strncmp (pBuf, "QUIT", 4) == 0)
{
/* sayonara */
ftpdCmdSend (pSlot, sock, 221, messages [MSG_SEE_YOU_LATER],
0, 0, 0, 0, 0, 0);
ftpdSessionDelete (pSlot);
return OK;
}
else if (strncmp (pBuf, "HELP", 4) == 0)
{
/* send list of supported commands with multiple line response */
if (ftpdCmdSend (pSlot, sock, FTPD_MULTI_LINE | 214,
messages [MSG_COMMAND_LIST_BEGIN], 0, 0, 0, 0, 0, 0)
== ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
if (write (pSlot->cmdSock, ftpdCommandList,
strlen (ftpdCommandList)) <= 0)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
/* this signifies the end of the multiple line response */
if (ftpdCmdSend (pSlot, sock, 214, messages [MSG_COMMAND_LIST_END],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
continue; /* All is well go wait for the next command */
}
else if ((pSlot->status & FTPD_USER_OK) == 0) /* validated yet? */
{
/* user is not validated yet. tell him to log in first */
if (ftpdCmdSend (pSlot, sock, 530, messages [MSG_USER_PASS_REQ],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
/* do not proceed further until he's legit */
continue;
}
if (strncmp (pBuf, "LIST", 4) == 0 ||
strncmp (pBuf, "NLST", 4) == 0)
{
STATUS retVal;
/* client wants to list out the contents of a directory */
/* if no directory specified or "." specified as a directory
* we use the currently active directory name
*/
if (strlen (pBuf) < 6 || pBuf [5] == '.')
dirName = &pSlot->curDirName [0];
else if (pBuf [5] != '/')
{
if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
(void) sprintf (newPath,
"%s%s", pSlot->curDirName, &pBuf [5]);
else
(void) sprintf (newPath,
"%s/%s", pSlot->curDirName, &pBuf [5]);
dirName = newPath;
}
else
dirName = &pBuf [5];
ftpdDebugMsg ("LIST %s\n", (int)dirName,0,0,0);
/* get a new data socket connection for the transmission of
* the directory listing data
*/
if (ftpdDataConnGet (pSlot) == ERROR)
{
if (ftpdCmdSend (pSlot, sock,
426, messages [MSG_DATA_CONN_ERROR],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
continue;
}
/* print out the directory contents over the data connection */
retVal = ftpdDirListGet (pSlot->dataSock, dirName,
(strncmp (pBuf, "LIST", 4) == 0));
if (retVal == ERROR)
{
if (ftpdCmdSend (pSlot, sock, 550, messages [MSG_DIR_ERROR],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
}
else
{
if (ftpdCmdSend (pSlot, sock,
226, messages [MSG_TRANS_COMPLETE],
0, 0, 0, 0, 0, 0) == ERROR)
{
ftpdSessionDelete (pSlot);
return (ERROR);
}
}
/* free up the data socket */
ftpdSockFree (&pSlot->dataSock);
}
else if (strncmp (pBuf, "RETR", 4) == 0)
{
/* retrieve a file */
/* open the file to be sent to the client */
if (pBuf [5] != '/')
{
if (pSlot->curDirName [strlen (pSlot->curDirName) - 1] == '/')
(void) sprintf (newPath,
"%s%s", pSlot->curDirName, &pBuf [5]);
else
(void) sprintf (newPath,
"%s/%s", pSlot->curDirName, &pBuf [5]);
pFileName = newPath;
}
else
pFileName = &pBuf [5];
ftpdDebugMsg ("RETR %s\n", (int)pFileName,0,0,0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -