?? ftpdlib.c
字號:
FTPD_SESSION_DATA * pData; if (! ftpsActive) /* Automatic success if server is not running. */ return (OK); /* * Remove the FTP server task to prevent additional sessions from starting. * The exclusion semaphore guarantees a stable list of active clients. */ semTake (ftpsMutexSem, WAIT_FOREVER); taskDelete (ftpdTaskId); ftpdTaskId = -1; if (ftpsCurrentClients != 0) serverActive = TRUE; /* * Set the shutdown flag so that any secondary server tasks will exit * as soon as possible. Once the FTP server has started, this routine is * the only writer of the flag and the secondary tasks are the only * readers. To avoid unnecessary blocking, the secondary tasks do not * guard access to this flag when checking for a pending shutdown during * normal processing. Those tasks do protect access to this flag during * their cleanup routine to prevent a race condition which would result * in incorrect use of the signalling semaphore. */ ftpsShutdownFlag = TRUE; /* * Close the command sockets of any active sessions to prevent further * activity. If the session is waiting for a command from a socket, * the close will trigger the session exit. */ pData = (FTPD_SESSION_DATA *)lstFirst (&ftpsSessionList); while (pData != NULL) { ftpdSockFree (&pData->cmdSock); pData = (FTPD_SESSION_DATA *)lstNext (&pData->node); } semGive (ftpsMutexSem); /* Wait for all secondary tasks to exit. */ if (serverActive) { /* * When a shutdown is in progress, the cleanup routine of the last * client task to exit gives the signalling semaphore. */ semTake (ftpsSignalSem, WAIT_FOREVER); } /* * Remove the original socket - this occurs after all secondary tasks * have exited to avoid prematurely closing their control sockets. */ ftpdSockFree (&ftpdServerSock); /* Remove the protection and signalling semaphores and list of clients. */ lstFree (&ftpsSessionList); /* Sanity check - should already be empty. */ semDelete (ftpsMutexSem); semDelete (ftpsSignalSem); ftpsActive = FALSE; return (OK); }/********************************************************************************* ftpdSessionAdd - add a new entry to the ftpd session slot list** Each of the incoming FTP sessions is associated with an entry in the* FTP server's session list which records session-specific context for each* control connection established by the FTP clients. This routine creates and* initializes a new entry in the session list, unless the needed memory is not* available or the upper limit for simultaneous connections is reached.** RETURNS: A pointer to the session list entry, or NULL of none available.** ERRNO: N/A** NOMANUAL** INTERNAL* This routine executes within a critical section of the primary FTP server* task, so mutual exclusion is already present when adding entries to the* client list and updating the shared variables indicating the current number* of connected clients.*/LOCAL FTPD_SESSION_DATA *ftpdSessionAdd (void) { FAST FTPD_SESSION_DATA *pSlot; if (ftpsCurrentClients >= ftpsMaxClients) return (NULL); /* get memory for the new session entry */ pSlot = (FTPD_SESSION_DATA *) calloc (sizeof (FTPD_SESSION_DATA), 1); if (pSlot == NULL) { return (NULL); } if (ftpdWindowSize < 0 || ftpdWindowSize > 65536) ftpdWindowSize = FTPD_WINDOW_SIZE; pSlot->bufSize = ftpdWindowSize ; ftpdDebugMsg ("allocating new session buffer %d bytes\n", pSlot->bufSize,0,0,0); pSlot->buf = malloc( pSlot->bufSize ); if( pSlot->buf == NULL ) { free(pSlot); return (NULL); } /* initialize key fields in the newly acquired slot */ pSlot->dataSock = FTPD_SOCK_FREE; pSlot->cmdSock = FTPD_SOCK_FREE; pSlot->cmdSockError = OK; pSlot->status = FTPD_STREAM_MODE | FTPD_BINARY_TYPE | FTPD_NO_RECORD_STRU; pSlot->byteCount = 0; /* assign the default directory for this guy */ if(defaultHomeDir[0] == EOS ) ioDefPathGet (pSlot->curDirName); else strcpy( defaultHomeDir, pSlot->curDirName); semTake (ftpsMutexSem, WAIT_FOREVER); /* Add new entry to the list of active sessions. */ lstAdd (&ftpsSessionList, &pSlot->node); ftpdNumTasks++; ftpsCurrentClients++; semGive (ftpsMutexSem); return (pSlot); }/********************************************************************************* ftpdSessionDelete - remove an entry from the FTP session list** This routine removes the session-specific context from the session list* after the client exits or a fatal error occurs.** RETURNS: N/A** ERRNO: N/A** NOMANUAL** INTERNAL* Unless an error occurs, this routine is only called in response to a* pending server shutdown, indicated by the shutdown flag. Even if the* shutdown flag is not detected and this routine is called because of an* error, the appropriate signal will still be sent to any pending shutdown* routine. The shutdown routine will only return after any active client* 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); free (pSlot->buf); free (pSlot); /* Send required signal if all sessions are closed. */ if (ftpsShutdownFlag) { if (ftpsCurrentClients == 0) semGive (ftpsSignalSem); } semGive (ftpsMutexSem); return; }/********************************************************************************* ftpPathAccessVerify - verify client access to a path**/LOCAL STATUS ftpPathAccessVerify ( FTPD_SESSION_DATA *pSlot, char * path, int mode ) { char * where ; int len; /* allways allow access if not anonymous user */ if( (pSlot->status & FTPD_ANONYMOUS) == 0 ) return (OK); if( mode == O_RDONLY ) { where = guestHomeDir ; } else { where = writeDirName ; } len = strlen(where); /* perform case-insensitive comparison a la strncmp() */ { FAST char *s1, *s2; FAST int i; for( s1 = where, s2 = path, i = 0; (*s1!=EOS && *s2!=EOS) && i<len; s1++, s2++, i-- ) { if(toupper(*s1) == toupper(*s2)) continue ; else goto deny; } } ftpdDebugMsg ("access mode %d allowed for path %s\n", mode, (int)path,0,0); return OK ;deny: ftpdDebugMsg ("access mode %d denied for path %s\n", mode, (int)path,0,0); return ERROR; }/********************************************************************************* ftpdPathForPrint - prepare a path to be printed to client**/LOCAL char * ftpdPathForPrint( FTPD_SESSION_DATA *pSlot, char * path ) { if( pSlot->status & FTPD_ANONYMOUS ) { int len = strlen( guestHomeDir ); if( strncmp( guestHomeDir, path, len) != 0) return NULL ; strcpy( path, path+len ); /* XXX - in-place copy */ } return(path); }/********************************************************************************* ftpPathNormalize - process path provided by client for use***/LOCAL void ftpPathNormalize ( FTPD_SESSION_DATA *pSlot, char * path, char * buffer, char ** pResult ) { if ( (strcmp(path,".") == 0) || (path[0] == EOS) ) { /* explicitly relative */ *pResult = &pSlot->curDirName [0]; return ; } (void) pathCat (pSlot->curDirName, path, buffer); pathCondense (buffer); /* condense ".." shit */ *pResult = buffer; }/********************************************************************************* 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, *pBufEnd;/* pointer to session specific buffer */ struct sockaddr_in passiveAddr; /* socket address in passive mode */ 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 renFile [MAX_FILENAME_LENGTH]; char newPath [MAX_FILENAME_LENGTH]; char *pFileName; FILE *outStream; char *upperCommand; /* convert command to uppercase */ pBuf = &pSlot->buf [0]; /* use session specific buffer area */ pBufEnd = pSlot->bufSize-1 + pBuf ;/* buffer limit */ 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 */ if (ftpdCmdSend (pSlot, sock, 220, messages [MSG_SERVER_READY], (int)vxWorksVersion, 0, 0, 0, 0, 0) == ERROR) goto connectionLost; FOREVER { taskDelay (0); /* time share among same priority tasks */ /* Check error in writting to the control socket */ if (pSlot->cmdSockError == ERROR) goto connectionLost; pSlot->byteCount = 0 ; (void) time( &pSlot->timeUsed ); /* refsh idle timer */ /* * 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; /* clean up cmd buffer, 8 chars should suffice */ bzero( pBuf, 8 ); /* get a request command */ FOREVER { taskDelay (0); /* time share among same priority tasks */ if ((numRead = read (sock, pBuf, 1)) <= 0) { /* * The primary server task will close the control connection
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -