ftpd.c
来自「RTEMS (Real-Time Executive for Multiproc」· C语言 代码 · 共 2,063 行 · 第 1/4 页
C
2,063 行
/* FIXME: 1. Parse command is a hack. We can do better. * 2. Some sort of access control? * 3. OSV: hooks support seems to be bad, as it requires storing of * entire input file in memory. Seem to be better to change it to * something more reasonable, like having * 'hook_write(void const *buf, int count)' routine that will be * called multiple times while file is being received. * 4. OSV: Remove hack with "/dev/null"? * * FTP Server Daemon * * Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu> * * Changed by: Sergei Organov <osv@javad.ru> (OSV) * * Changes: * * 2001-01-31 Sergei Organov <osv@javad.ru> * * * Hacks with current dir and root dir removed in favor of new libio * support for task-local current and root directories. * * 2001-01-30 Sergei Organov <osv@javad.ru> * * * Bug in `close_data_socket()' introduced by previous change fixed. * * `command_pasv()' changed to set timeout on socket we are listening on * and code fixed to don't close socket twice on error. * * `serr()' changed to clear `errno'. * * `data_socket()' changed to clear `errno' before `bind()'. * * `session()' changed to clear `errno' before processing session. * * 2001-01-29 Sergei Organov <osv@javad.ru> * * * `close_data_socket()' fixed to close both active and passive sockets * * Initialize info->data_socket to -1 in `daemon()' * * Initialize `fname' to empty string in `exec_command()' * * 2001-01-22 Sergei Organov <osv@javad.ru> * * * Timeouts on sockets implemented. 'idle' field added to * configuration. No timeout by default to keep backward compatibility. * Note: SITE IDLE command not implemented yet. * * Basic global access control implemented. 'access' field added to * configuration. No access limitations by default to keep backward * compatibility. * * 2001-01-17 Sergei Organov <osv@javad.ru> * * * Anchor data socket for active mode (using self IP and port 20.) * * Fixed default data port support (still not tested). * * Don't allow IP address different from originating host in * PORT command to improve security. * * Fixed bug in MDTM command. * * Check for correctness of parsing of argument in command_port(). * * Fixed squeeze_path() to don't allow names like 'NAME/smth' where * 'NAME' is not a directory. * * Command parsing a little bit improved: command names are now * converted to upper-case to be more compatible with RFC (command * names are not case-sensitive.) * * Reformat comments so that they have RTEMS look-and-feel. * * 2001-01-16 Sergei Organov <osv@javad.ru> * * * Fixed DELE, SITE CHMOD, RMD, MKD broken by previous changes * * True ASCII mode implemented (doesn't work for hooks and /dev/null) * * Passive mode implemented, PASV command added. * * Default port for data connection could be used (untested, can't find * ftp client that doesn't send PORT command) * * SYST reply changed to UNIX, as former RTEMS isn't registered name. * * Reply codes reviewed and fixed. * * 2001-01-08 Sergei Organov <osv@javad.ru> * * * use pool of pre-created threads to handle sessions * * LIST output now similar to what "/bin/ls -al" would output, thus * FTP clients could parse it. * * LIST NAME now works (both for files and directories) * * keep track of CWD for every session separately * * ability to specify root directory name in configuration table * * options sent in commands are ignored, thus LIST -al FILE works * * added support for NLST, CDUP and MDTM commands * * buffers are allocated on stack instead of heap where possible * * drop using of task notepad to pass parameters - use function * arguments instead * * various bug-fixes, e.g., use of PF_INET in socket() instead of * AF_INET, use snprintf() instead of sprintf() everywhere for safety, * etc. * * $Id: ftpd.c,v 1.9 2002/09/07 23:07:58 joel Exp $ *//************************************************************************* * ftpd.c ************************************************************************* * Description: * * This file contains the daemon which services requests that appear * on the FTP port. This server is compatible with FTP, but it * also provides 'hooks' to make it usable in situations where files * are not used/necessary. Once the server is started, it runs * forever. * * * Organization: * * The FTP daemon is started upon boot along with a (configurable) * number of tasks to handle sessions. It runs all the time and * waits for connections on the known FTP port (21). When * a connection is made, it wakes-up a 'session' task. That * session then interacts with the remote host. When the session * is complete, the session task goes to sleep. The daemon still * runs, however. * * * Supported commands are: * * RETR xxx - Sends a file from the client. * STOR xxx - Receives a file from the client. xxx = filename. * LIST xxx - Sends a file list to the client. * NLST xxx - Sends a file list to the client. * USER - Does nothing. * PASS - Does nothing. * SYST - Replies with the system type (`RTEMS'). * DELE xxx - Delete file xxx. * MKD xxx - Create directory xxx. * RMD xxx - Remove directory xxx. * PWD - Print working directory. * CWD xxx - Change working directory. * CDUP - Change to upper directory. * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx. * PORT a,b,c,d,x,y - Setup for a data port to IP address a.b.c.d * and port (x*256 + y). * MDTM xxx - Send file modification date/time to the client. * xxx = filename. * PASV - Use passive mode data connection. * * * The public routines contained in this file are: * * rtems_initialize_ftpd - Initializes and starts the server daemon, * then returns to its caller. * *------------------------------------------------------------------------ * Jake Janovetz * University of Illinois * 1406 West Green Street * Urbana IL 61801 ************************************************************************* * Change History: * 12/01/97 - Creation (JWJ) * 2001-01-08 - Changes by OSV *************************************************************************//************************************************************************* * Meanings of first and second digits of reply codes: * * Reply: Description: *-------- -------------- * 1yz Positive preliminary reply. The action is being started but * expect another reply before sending another command. * 2yz Positive completion reply. A new command can be sent. * 3yz Positive intermediate reply. The command has been accepted * but another command must be sent. * 4yz Transient negative completion reply. The requested action did * not take place, but the error condition is temporary so the * command can be reissued later. * 5yz Permanent negative completion reply. The command was not * accepted and should not be retried. *------------------------------------------------------------------------- * x0z Syntax errors. * x1z Information. * x2z Connections. Replies referring to the control or data * connections. * x3z Authentication and accounting. Replies for the login or * accounting commands. * x4z Unspecified. * x5z Filesystem status. *************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <dirent.h>#include <errno.h>#include <ctype.h>#include <rtems.h>#include <rtems/rtems_bsdnet.h>#include <rtems/error.h>#include <rtems/libio.h>#include <rtems/userenv.h>#include <syslog.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/ftp.h>#include <netinet/in.h>#include "ftpd.h"#ifdef __GNUC__/* change to #if 1 to disable syslog entirely */#if 0#undef syslog#define syslog(a, b, ...) while(0){}#endif#endif#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.1-JWJ) ready."#define FTPD_SYSTYPE "UNIX Type: L8"/* Seem to be unused */#if 0#define FTPD_WELCOME_MESSAGE \ "Welcome to the RTEMS FTP server.\n" \ "\n" \ "Login accepted.\n"#endif/* Various buffer sizes */enum{ FTPD_BUFSIZE = 256, /* Size for temporary buffers */ FTPD_DATASIZE = 1024, /* Size for file transfer buffers */ FTPD_STACKSIZE = 8 * 1024, /* Tasks stack size */};/* Event to be used by session tasks for waiting */enum{ FTPD_RTEMS_EVENT = RTEMS_EVENT_1};/* Configuration table */extern struct rtems_ftpd_configuration rtems_ftpd_configuration;/* this is not prototyped in strict ansi mode */FILE *fdopen (int fildes, const char *mode);/*PAGE * SessionInfo structure. * * The following structure is allocated for each session. */typedef struct{ struct sockaddr_in ctrl_addr; /* Control connection self address */ struct sockaddr_in data_addr; /* Data address set by PORT command */ struct sockaddr_in def_addr; /* Default address for data */ int use_default; /* 1 - use default address for data */ FILE *ctrl_fp; /* File pointer for control connection */ int ctrl_socket; /* Socket for ctrl connection */ int pasv_socket; /* Socket for PASV connection */ int data_socket; /* Socket for data connection */ int idle; /* Timeout in seconds */ int xfer_mode; /* Transfer mode (ASCII/binary) */ rtems_id tid; /* Task id */} FTPD_SessionInfo_t;/* * TaskPool structure. */typedef struct{ FTPD_SessionInfo_t *info; FTPD_SessionInfo_t **queue; int count; int head; int tail; rtems_id mutex; rtems_id sem;} FTPD_TaskPool_t;/* * Task pool instance. */static FTPD_TaskPool_t task_pool;/* * Root directory */static char const* ftpd_root = "/";/* * Default idle timeout for sockets in seconds. */static int ftpd_timeout = 0;/* * Global access flags. */static int ftpd_access = 0;/*PAGE * * serr * * Return error string corresponding to current 'errno'. * */static char const*serr(void){ int err = errno; errno = 0; return strerror(err);}/*PAGE * * Utility routines for access control. * */static intcan_read(void){ return (ftpd_access & FTPD_NO_READ) == 0;}static intcan_write(void){ return (ftpd_access & FTPD_NO_WRITE) == 0;}/*PAGE * * Task pool management routines * *//*PAGE * * task_pool_done * * Cleanup task pool. * * Input parameters: * count - number of entries in task pool to cleanup * * Output parameters: * NONE * */static voidtask_pool_done(int count){ int i; for(i = 0; i < count; ++i) rtems_task_delete(task_pool.info[i].tid); if(task_pool.info) free(task_pool.info); if(task_pool.queue) free(task_pool.queue); if(task_pool.mutex != (rtems_id)-1) rtems_semaphore_delete(task_pool.mutex); if(task_pool.sem != (rtems_id)-1) rtems_semaphore_delete(task_pool.sem); task_pool.info = 0; task_pool.queue = 0; task_pool.count = 0; task_pool.sem = -1; task_pool.mutex = -1;}/*PAGE * * task_pool_init * * Initialize task pool. * * Input parameters: * count - number of entries in task pool to create * priority - priority tasks are started with * * Output parameters: * returns 1 on success, 0 on failure. * */static void session(rtems_task_argument arg); /* Forward declare */static inttask_pool_init(int count, rtems_task_priority priority){ int i; rtems_status_code sc; char id = 'a'; task_pool.count = 0; task_pool.head = task_pool.tail = 0; task_pool.mutex = (rtems_id)-1; task_pool.sem = (rtems_id)-1; sc = rtems_semaphore_create( rtems_build_name('F', 'T', 'P', 'M'), 1, RTEMS_DEFAULT_ATTRIBUTES | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, RTEMS_NO_PRIORITY, &task_pool.mutex); if(sc == RTEMS_SUCCESSFUL) sc = rtems_semaphore_create( rtems_build_name('F', 'T', 'P', 'S'), count, RTEMS_DEFAULT_ATTRIBUTES, RTEMS_NO_PRIORITY, &task_pool.sem); if(sc != RTEMS_SUCCESSFUL) { task_pool_done(0); syslog(LOG_ERR, "ftpd: Can not create semaphores"); return 0; } task_pool.info = (FTPD_SessionInfo_t*) malloc(sizeof(FTPD_SessionInfo_t) * count); task_pool.queue = (FTPD_SessionInfo_t**) malloc(sizeof(FTPD_SessionInfo_t*) * count); if (NULL == task_pool.info || NULL == task_pool.queue) { task_pool_done(0); syslog(LOG_ERR, "ftpd: Not enough memory"); return 0; } for(i = 0; i < count; ++i) { FTPD_SessionInfo_t *info = &task_pool.info[i]; sc = rtems_task_create(rtems_build_name('F', 'T', 'P', id), priority, FTPD_STACKSIZE, RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0), RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL, &info->tid); if (sc == RTEMS_SUCCESSFUL) { sc = rtems_task_start( info->tid, session, (rtems_task_argument)info); if (sc != RTEMS_SUCCESSFUL) task_pool_done(i); } else task_pool_done(i + 1); if (sc != RTEMS_SUCCESSFUL) { syslog(LOG_ERR, "ftpd: Could not create/start FTPD session: %s", rtems_status_text(sc)); return 0; } task_pool.queue[i] = task_pool.info + i; if (++id > 'z') id = 'a'; } task_pool.count = count; return 1;}/*PAGE * * task_pool_obtain * * Obtain free task from task pool. * * Input parameters: * NONE * * Output parameters: * returns pointer to the corresponding SessionInfo structure on success, * NULL if there are no free tasks in the pool. * */static FTPD_SessionInfo_t*task_pool_obtain(){ FTPD_SessionInfo_t* info = 0; rtems_status_code sc; sc = rtems_semaphore_obtain(task_pool.sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); if (sc == RTEMS_SUCCESSFUL) { rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); info = task_pool.queue[task_pool.head]; if(++task_pool.head >= task_pool.count) task_pool.head = 0; rtems_semaphore_release(task_pool.mutex); } return info;}/*PAGE * * task_pool_release * * Return task obtained by 'obtain()' back to the task pool. * * Input parameters: * info - pointer to corresponding SessionInfo structure. * * Output parameters: * NONE * */static voidtask_pool_release(FTPD_SessionInfo_t* info){ rtems_semaphore_obtain(task_pool.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?