?? ftpdlib.c
字號:
"\"%s\" directory could not be created", "Timeout (%d seconds): closing connection.", "Guest login ok, send your complete e-mail address as password.", "Guest login ok, access restrictions apply.", "Guest login ok, upload directory is %s.", "Guest access denied.", };/* Indexes to the messages [] array */#define MSG_PASSIVE_ERROR 0#define MSG_PARAM_BAD 1#define MSG_DATA_CONN_ERROR 2#define MSG_DIR_NOT_PRESENT 3#define MSG_LOCAL_RESOURCE_FAIL 4#define MSG_SERVER_READY 5#define MSG_PASSWORD_REQUIRED 6#define MSG_USER_LOGGED_IN 7#define MSG_SEE_YOU_LATER 8#define MSG_USER_PASS_REQ 9#define MSG_DIR_ERROR 10#define MSG_TRANS_COMPLETE 11#define MSG_FILE_ERROR 12#define MSG_CREATE_ERROR 13#define MSG_CHANGED_DIR 14#define MSG_TYPE_BINARY 15#define MSG_TYPE_ASCII 16#define MSG_PORT_SET 17#define MSG_CUR_DIR 18#define MSG_FILE_STRU 19#define MSG_STREAM_MODE 20#define MSG_ALLOC_ACCOUNT 21#define MSG_PASSIVE_MODE 22#define MSG_NOOP_OKAY 23#define MSG_BAD_COMMAND 24#define MSG_INPUT_FILE_ERROR 25#define MSG_TYPE_ERROR 26#define MSG_NO_GOOD_BYE 27#define MSG_COMMAND_LIST_BEGIN 28#define MSG_COMMAND_LIST_END 29#define MSG_DELE_OK 30#define MSG_USER_LOGIN_FAILED 31#define MSG_RNFR_OK 32#define MSG_RNTO_OK 33#define MSG_MKD_OK 34#define MSG_RMD_OK 35#define MSG_FILE_NOTREG 36#define MSG_SYST_REPLY 37#define MSG_MKD_ERROR 38#define MSG_CONN_TIMEOUT 39#define MSG_GUEST_PASS 40#define MSG_GUEST_OK 41#define MSG_GUEST_UPLOAD_OK 42#define MSG_GUEST_ACCESS 43LOCAL char *ftpdCommandList ="HELP USER PASS QUIT LIST NLST\n\RETR STOR CWD TYPE PORT PWD\n\STRU MODE ALLO ACCT PASV NOOP\n\DELE RNFR RNTO MKD RMD MDTM\n\SIZE SYST XCWD XPWD XMKD XRMD\n";/* forward declarations */LOCAL FTPD_SESSION_DATA *ftpdSessionAdd (void);LOCAL void ftpdSessionDelete (FTPD_SESSION_DATA *);LOCAL STATUS ftpdWorkTask (FTPD_SESSION_DATA *);LOCAL STATUS ftpdCmdSend (FTPD_SESSION_DATA *, int, int, const char *, int, int, int, int, int, int);LOCAL STATUS ftpdDataConnGet (FTPD_SESSION_DATA *);LOCAL void ftpdDataStreamSend (FTPD_SESSION_DATA *, char *);LOCAL STATUS ftpdDataStreamReceive (FTPD_SESSION_DATA *, FILE *outStream);LOCAL void ftpdSockFree (int *);LOCAL STATUS ftpdDirListGet (int, char *, BOOL);LOCAL void ftpdDebugMsg (char *, int, int, int, int);LOCAL void unImplementedType (FTPD_SESSION_DATA *pSlot);LOCAL void dataError (FTPD_SESSION_DATA *pSlot);LOCAL void fileError (FTPD_SESSION_DATA *pSlot);LOCAL void transferOkay (FTPD_SESSION_DATA *pSlot);/* rmdir() is implemented by simply calling remove() */#define rmdir(dName) remove((dName))/* mkdir() is implemented locally to avoid unnecesary dependency */#define mkdir(dName) ftpMkdir((dName))/********************************************************************************* ftpMkdir - make a directory** This command creates a new directory in a hierarchical file system.* The <dirName> string specifies the name to be used for the* new directory, and can be either a full or relative pathname.* This function is replicated here to avoid dependency in usrLib or* usrFsLib.*/LOCAL STATUS ftpMkdir ( char *dirName /* directory name */ ) { int fd; if ((fd = open (dirName, O_RDWR | O_CREAT, FSTAT_DIR | DEFAULT_DIR_PERM)) == ERROR) { return (ERROR); } return (close (fd)); }/********************************************************************************* ftpdTask - FTP server daemon task** This routine monitors the FTP control port for incoming requests from clients* and processes each request by spawning a secondary server task after * establishing the control connection. If the maximum number of connections is* reached, it returns the appropriate error to the requesting client. The * routine is the entry point for the primary FTP server task and should only* be called internally.** RETURNS: N/A** ERRNO: N/A** INTERNAL:* The server task is deleted by the server shutdown routine. Adding a newly* created client session to the list of active clients is performed atomically* with respect to the shutdown routine. However, accepting control connections* is not a critical section, since closing the initial socket used in the* listen() call also closes any later connections which are still open.** NOMANUAL*/LOCAL void ftpdTask (void) { int newSock; FAST FTPD_SESSION_DATA *pSlot; int on = 1; int addrLen; struct sockaddr_in addr; char a_ip_addr [INET_ADDR_LEN]; /* ascii ip address of client */ ftpdNumTasks = 0; /* The following loop halts if this task is deleted. */ FOREVER { /* Wait for a new incoming connection. */ addrLen = sizeof (struct sockaddr); ftpdDebugMsg ("waiting for a new client connection...\n",0,0,0,0); newSock = accept (ftpdServerSock, (struct sockaddr *) &addr, &addrLen); if (newSock < 0) { ftpdDebugMsg ("cannot accept a new connection\n",0,0,0,0); break; } /* * Register a new FTP client session. This process is a critical * section with the server shutdown routine. If an error occurs, * the reply must be sent over the control connection to the peer * before the semaphore is released. Otherwise, this task could * be deleted and no response would be sent, possibly causing * the new client to hang indefinitely. */ semTake (ftpsMutexSem, WAIT_FOREVER); setsockopt (newSock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); inet_ntoa_b (addr.sin_addr, a_ip_addr); ftpdDebugMsg ("accepted a new client connection from %s\n", (int) a_ip_addr, 0, 0, 0); /* scan the connections to shutdown any connection which is idle */ pSlot = (FTPD_SESSION_DATA *)lstFirst (&ftpsSessionList); while (pSlot != NULL) { FTPD_SESSION_DATA * pNext ; time_t now = time(NULL); /* need next now, cuz it can be destroyed */ pNext = (FTPD_SESSION_DATA *)lstNext (&pSlot->node); if( (now - pSlot->timeUsed) > FTPD_CONN_TIMEOUT ) { ftpdDebugMsg("session %x idle byteCount %d\n", (int) pSlot, pSlot->byteCount, 0, 0); if ( pSlot->byteCount == 0 ) { ftpdCmdSend (pSlot, pSlot->cmdSock, 421, messages [MSG_CONN_TIMEOUT], now - pSlot->timeUsed, 0, 0, 0, 0, 0); ftpdDebugMsg("deleting session %x\n", (int)pSlot, 0, 0, 0); /* XXX ftpdSessionDelete( pSlot ); */ ftpdSockFree (&pSlot->cmdSock); taskDelay( sysClkRateGet() / 10 ); } else pSlot->byteCount = 0 ; } pSlot = pNext ; } /* Create a new session entry for this connection, if possible. */ pSlot = ftpdSessionAdd (); if (pSlot == NULL) /* Maximum number of connections reached. */ { /* Send transient failure report to client. */ ftpdCmdSend (pSlot, newSock, 421, "Session limit reached, closing control connection", 0, 0, 0, 0, 0, 0); ftpdDebugMsg ("cannot get a new connection slot\n",0,0,0,0); semGive (ftpsMutexSem); continue; } pSlot->cmdSock = newSock; /* Save the control address and assign the default data address. */ bcopy ( (char *)&addr, (char *)&pSlot->peerAddr, sizeof (struct sockaddr_in)); bcopy ( (char *)&addr, (char *)&pSlot->dataAddr, sizeof (struct sockaddr_in)); pSlot->dataAddr.sin_port = htons (FTP_DATA_PORT); /* Create a task name. */ sprintf (ftpdWorkTaskName, "tFtpdServ%d", ftpdNumTasks); /* Spawn a secondary task to process FTP requests for this session. */ ftpdDebugMsg ("creating a new server task %s...\n", (int) ftpdWorkTaskName, 0, 0, 0); if (taskSpawn (ftpdWorkTaskName, ftpdWorkTaskPriority, ftpdWorkTaskOptions, ftpdWorkTaskStackSize, ftpdWorkTask, (int) pSlot, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR) { /* Send transient failure report to client. */ ftpdCmdSend (pSlot, newSock, 421, "Service not available, closing control connection", 0, 0, 0, 0, 0, 0); ftpdSessionDelete (pSlot); ftpdDebugMsg ("cannot create a new work task\n",0,0,0,0); semGive (ftpsMutexSem); continue; } ftpdDebugMsg ("done.\n",0,0,0,0); /* Session added - end of critical section with shutdown routine. */ semGive (ftpsMutexSem); } /* Fatal error - update state of server. */ ftpsActive = FALSE; return; }/********************************************************************************* ftpdInit - initialize the FTP server task** This routine spawns the FTP server task,* and establishes a control connection for it on the well-knoen* FTP service port, or on another port if a non-zero value is* specified with the <port> argiment.** Usually it is called automatically during system startup* if INCLUDE_FTP_SERVER is defined. The primary server task * supports simultaneous client sessions, up to the limit specified by the * global variable 'ftpsMaxClients'. The default value allows a maximum of * four simultaneous connections. The <stackSize> argument specifies the stack * size for the primary server task. It is set to the value specified in the * 'ftpdWorkTaskStackSize' global variable by default.** RETURNS:* OK if server started, or ERROR otherwise.** ERRNO: N/A*/STATUS ftpdInit ( int port, /* service port */ int stackSize /* task stack size, or 0 for default */ ) { int on = 1; struct sockaddr_in ctrlAddr; if (ftpsActive) return (OK); ftpsShutdownFlag = FALSE; ftpsCurrentClients = 0; /* Create the FTP server control socket. */ ftpdServerSock = socket (AF_INET, SOCK_STREAM, 0); if (ftpdServerSock < 0) return (ERROR); /* Create data structures for managing client connections. */ lstInit (&ftpsSessionList); ftpsMutexSem = semMCreate (SEM_Q_FIFO | SEM_DELETE_SAFE); if (ftpsMutexSem == NULL) { close (ftpdServerSock); return (ERROR); } ftpsSignalSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY); if (ftpsSignalSem == NULL) { close (ftpdServerSock); semDelete (ftpsMutexSem); return (ERROR); } /* Setup control connection for client requests. */ if ( port == 0 ) port = FTP_DAEMON_PORT ; ctrlAddr.sin_family = AF_INET; ctrlAddr.sin_addr.s_addr = INADDR_ANY; ctrlAddr.sin_port = htons ( port ); if (setsockopt (ftpdServerSock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) { close (ftpdServerSock); semDelete (ftpsMutexSem); semDelete (ftpsSignalSem); return (ERROR); } if (bind (ftpdServerSock, (struct sockaddr *) &ctrlAddr, sizeof (ctrlAddr)) < 0) { close (ftpdServerSock); semDelete (ftpsMutexSem); semDelete (ftpsSignalSem); return (ERROR); } if (listen (ftpdServerSock, 5) < 0) { close (ftpdServerSock); semDelete (ftpsMutexSem); semDelete (ftpsSignalSem); return (ERROR); } /* Create a FTP server task to receive client requests. */ ftpdTaskId = taskSpawn ("tFtpdTask", ftpdTaskPriority - 1, ftpdTaskOptions, stackSize == 0 ? ftpdWorkTaskStackSize : stackSize, (FUNCPTR) ftpdTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (ftpdTaskId == ERROR) { ftpdDebugMsg ("ERROR: ftpdTask cannot be created\n",0,0,0,0); close (ftpdServerSock); semDelete (ftpsMutexSem); semDelete (ftpsSignalSem); return (ERROR); /* errno set by taskSpawn() */ } ftpsActive = TRUE; ftpdDebugMsg ("ftpdTask created\n",0,0,0,0); return (OK); }/********************************************************************************* ftpdDelete - terminate the FTP server task** This routine halts the FTP server and closes the control connection. All* client sessions are removed after completing any commands in progress.* When this routine executes, no further client connections will be accepted* until the server is restarted. This routine is not reentrant and must not* be called from interrupt level.** NOTE: If any file transfer operations are in progress when this routine is* executed, the transfers will be aborted, possibly leaving incomplete files* on the destination host.** RETURNS: OK if shutdown completed, or ERROR otherwise.** ERRNO: N/A** INTERNAL* This routine is synchronized with the deletion routine for a client session* so that the exit of the client tasks can be detected. It also shares a* critical section with the creation of client sessions to prevent orphaned* tasks, which would occur if a session were added after this routine had* shut down all known clients.*/STATUS ftpdDelete (void) { BOOL serverActive = FALSE;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -