/* FIXME: 1. Parse command is a hack. We can do better.
* 2. chdir is a hack. We can do better.
* 3. PWD doesn't work.
* 4. Some sort of access control?
*
* FTP Server Daemon
*
* Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
*
* $Id$
*/
/**************************************************************************
* 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. It runs all the time *
* and waits for connections on the known FTP port (21). When *
* a connection is made, it starts a 'session' task. That *
* session then interacts with the remote host. When the session *
* is complete, the session task deletes itself. 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. *
* (LIST xxx isn't working yet...) *
* 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. *
* 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). *
* *
* *
* The public routines contained in this file are: *
* *
* rtems_initialize_ftpd_start - Starts the server daemon, then *
* returns to its caller. *
* *
* *
* The private routines contained in this file are: *
* *
* rtems_ftpd_send_reply - Sends a reply code and text through the *
* control port. *
* rtems_ftpd_command_retrieve - Performs to "RETR" command. *
* rtems_ftpd_command_store - Performs the "STOR" command. *
* rtems_ftpd_command_list - Performs the "LIST" command. *
* rtems_ftpd_command_port - Opens a data port (the "PORT" command). *
* rtems_ftpd_parse_command - Parses an incoming command. *
* rtmes_ftpd_session - Begins a service session. *
* rtems_ftpd_daemon - Listens on the FTP port for service *
* requests. *
*------------------------------------------------------------------------*
* Jake Janovetz *
* University of Illinois *
* 1406 West Green Street *
* Urbana IL 61801 *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <rtems.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/error.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/ftp.h>
#include <netinet/in.h>
#include "ftpd.h"
extern struct rtems_ftpd_configuration rtems_ftpd_configuration;
/**************************************************************************
* 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 accpeted
* 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.
*************************************************************************/
/**************************************************************************
* SessionInfo structure.
*
* The following structure is allocated for each session. The pointer
* to this structure is contained in the tasks notepad entry.
*************************************************************************/
typedef struct
{
struct sockaddr_in data_addr; /* Data address for PORT commands */
FILE *ctrl_fp; /* File pointer for control connection */
char cwd[255]; /* Current working directory */
/* Login -- future use -- */
int xfer_mode; /* Transfer mode (ASCII/binary) */
} FTPD_SessionInfo_t;
#define FTPD_SERVER_MESSAGE "RTEMS FTP server (Version 1.0-JWJ) ready."
#define FTPD_WELCOME_MESSAGE \
"Welcome to the RTEMS FTP server.\n" \
"\n" \
"Login accepted.\n"
/**************************************************************************
* Function: rtems_ftpd_send_reply *
**************************************************************************
* Description: *
* *
* This procedure sends a reply to the client via the control *
* connection. *
* *
* *
* Inputs: *
* *
* int code - The 3-digit reply code. *
* char *text - Reply text. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
rtems_ftpd_send_reply(int code, char *text)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
char str[80];
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
/***********************************************************************
* code must be a 3-digit number.
**********************************************************************/
if ((code < 100) || (code > 999))
{
syslog(LOG_ERR, "ftpd: Code not 3-digits.");
return;
}
/***********************************************************************
* If a text reply exists, add it to the reply data.
**********************************************************************/
if (text != NULL)
{
sprintf(str, "%d %.70s\r\n", code, text);
fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
}
else
{
sprintf(str, "%d\r\n", code);
fprintf(info->ctrl_fp, "%d\r\n", code);
}
fflush(info->ctrl_fp);
}
/**************************************************************************
* Function: rtems_ftpd_command_retrieve *
**************************************************************************
* Description: *
* *
* This performs the "RETR" command. A data connection must already *
* be open (via the "PORT" command.) Here, we send the data to the *
* connection. *
* *
* *
* Inputs: *
* *
* char *filename - Source filename. *
* *
* Output: *
* *
* int - 0 for reply sent. *
* 1 for no reply sent. *
* *
**************************************************************************
* Change History: *
* 04/29/98 - Creation (JWJ) *
*************************************************************************/
static int
rtems_ftpd_command_retrieve(char *filename)
{
int s;
int n;
int fd;
unsigned char *bufr;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if ((fd = open(filename, O_RDONLY)) == -1)
{
rtems_ftpd_send_reply(450, "Error opening file.");
return(0);
}
bufr = (unsigned char *)malloc(BUFSIZ);
if (bufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
close(fd);
return(0);
}
/***********************************************************************
* Connect to the data connection (PORT made in an earlier PORT call).
**********************************************************************/
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
rtems_ftpd_send_reply(420, "Server error - could not connect socket.");
free(bufr);
close(fd);
close(s);
return(1);
}
/***********************************************************************
* Send the data over the ether.
**********************************************************************/
while ((n = read(fd, bufr, BUFSIZ)) > 0)
{
send(s, bufr, n, 0);
bufr[n-1] = '\0';
}
if (n == 0)
{
rtems_ftpd_send_reply(210, "File sent successfully.");
}
else
{
rtems_ftpd_send_reply(450, "Retrieve failed.");
}
if (close(s) != 0)
{
syslog(LOG_ERR, "ftpd: Error closing data socket");
}
free(bufr);
close(fd);
return(0);
}
/**************************************************************************
* Function: rtems_ftpd_command_store *
**************************************************************************
* Description: *
* *
* This performs the "STOR" command. A data connection must already *
* be open (via the "PORT" command.) Here, we get the data from the *
* connection and figure out what to do with it. *
* *
* *
* Inputs: *
* *
* char *filename - Destination filename. *
* *
* Output: *
* *
* int - 0 for success. *
* 1 for failure. *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static int
rtems_ftpd_command_store(char *filename)
{
char *bufr;
int s;
int n;
unsigned long size = 0;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
struct rtems_ftpd_hook *usehook = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
bufr = (char *)malloc(BUFSIZ * sizeof(char));
if (bufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
return(1);
}
rtems_ftpd_send_reply(150, "BINARY data connection.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
free(bufr);
close(s);
return(1);
}
/***********************************************************************
* File: "/dev/null" just throws the data away.
* Otherwise, search our list of hooks to see if we need to do something
* special.
**********************************************************************/
if (!strncmp("/dev/null", filename, 9))
{
while ((n = read(s, bufr, BUFSIZ)) > 0);
}
else if (rtems_ftpd_configuration.hooks != NULL)
{
struct rtems_ftpd_hook *hook;
int i;
i = 0;
hook = &rtems_ftpd_configuration.hooks[i++];
while (hook->filename != NULL)
{
if (!strcmp(hook->filename, filename))
{
usehook = hook;
break;
}
hook = &rtems_ftpd_configuration.hooks[i++];
}
}
if (usehook != NULL)
{
char *bigBufr;
/***********************************************************************
* Allocate space for our "file".
**********************************************************************/
bigBufr = (char *)malloc(
rtems_ftpd_configuration.max_hook_filesize * sizeof(char));
if (bigBufr == NULL)
{
rtems_ftpd_send_reply(440, "Server error - malloc fail.");
free(bufr);
return(1);
}
/***********************************************************************
* Retrieve the file into our buffer space.
**********************************************************************/
size = 0;
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
if (size + n >
rtems_ftpd_configuration.max_hook_filesize * sizeof(char))
{
rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded.");
free(bufr);
free(bigBufr);
close(s);
return(1);
}
memcpy(&bigBufr[size], bufr, n);
size += n;
}
close(s);
/***********************************************************************
* Call our hook.
**********************************************************************/
if ((usehook->hook_function)(bigBufr, size) == 0)
{
rtems_ftpd_send_reply(210, "File transferred successfully.");
}
else
{
rtems_ftpd_send_reply(440, "File transfer failed.");
}
free(bigBufr);
}
else
{
int fd;
size_t written;
fd = creat(filename, S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH);
if (fd == -1)
{
rtems_ftpd_send_reply(450, "Could not open file.");
close(s);
free(bufr);
return(1);
}
while ((n = read(s, bufr, BUFSIZ)) > 0)
{
written = write(fd, bufr, n);
if (written == -1)
{
rtems_ftpd_send_reply(450, "Error during write.");
close(fd);
close(s);
free(bufr);
return(1);
}
}
close(fd);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
}
free(bufr);
return(0);
}
/**************************************************************************
* Function: rtems_ftpd_command_list *
**************************************************************************
* Description: *
* *
* Sends a file list through a data connection. The data *
* connection must have already been opened with the "PORT" command. *
* *
* *
* Inputs: *
* *
* char *fname - File (or directory) to list. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
rtems_ftpd_command_list(char *fname)
{
int s;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
DIR *dirp;
struct dirent *dp;
char dirline[255];
struct stat stat_buf;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
rtems_ftpd_send_reply(150, "ASCII data connection for LIST.");
s = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s, (struct sockaddr *)&info->data_addr,
sizeof(struct sockaddr)) < 0)
{
syslog(LOG_ERR, "ftpd: Error connecting to data socket.");
return;
}
if ((dirp = opendir(fname)) == NULL)
{
sprintf(dirline, "%s: No such file or directory.%s\n",
fname, (info->xfer_mode==TYPE_A)?("\r"):(""));
send(s, dirline, strlen(dirline), 0);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
return;
}
while ((dp = readdir(dirp)) != NULL)
{
if (stat(dp->d_name, &stat_buf) == 0)
{
sprintf(dirline, "%c%c%c%c%c%c%c%c%c%c %5d %5d %11d %s%s\n",
(S_ISLNK(stat_buf.st_mode)?('l'):
(S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
(stat_buf.st_mode & S_IRUSR)?('r'):('-'),
(stat_buf.st_mode & S_IWUSR)?('w'):('-'),
(stat_buf.st_mode & S_IXUSR)?('x'):('-'),
(stat_buf.st_mode & S_IRGRP)?('r'):('-'),
(stat_buf.st_mode & S_IWGRP)?('w'):('-'),
(stat_buf.st_mode & S_IXGRP)?('x'):('-'),
(stat_buf.st_mode & S_IROTH)?('r'):('-'),
(stat_buf.st_mode & S_IWOTH)?('w'):('-'),
(stat_buf.st_mode & S_IXOTH)?('x'):('-'),
(int)stat_buf.st_uid,
(int)stat_buf.st_gid,
(int)stat_buf.st_size,
dp->d_name,
(info->xfer_mode==TYPE_A)?("\r"):(""));
send(s, dirline, strlen(dirline), 0);
}
}
closedir(dirp);
close(s);
rtems_ftpd_send_reply(226, "Transfer complete.");
}
/*
* Cheesy way to change directories
*/
static void
rtems_ftpd_CWD(char *dir)
{
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if (chdir(dir) == 0)
{
rtems_ftpd_send_reply(250, "CWD command successful.");
}
else
{
rtems_ftpd_send_reply(550, "CWD command failed.");
}
}
/**************************************************************************
* Function: rtems_ftpd_command_port *
**************************************************************************
* Description: *
* *
* This procedure opens up a data port given the IP address of the *
* remote machine and the port on the remote machine. This connection *
* will then be used to transfer data between the hosts. *
* *
* *
* Inputs: *
* *
* char *bufr - Arguments to the "PORT" command. *
* *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
rtems_ftpd_command_port(char *bufr)
{
char *ip;
char *port;
int ip0, ip1, ip2, ip3, port0, port1;
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1);
ip = (char *)&(info->data_addr.sin_addr);
ip[0] = ip0 & 0xff;
ip[1] = ip1 & 0xff;
ip[2] = ip2 & 0xff;
ip[3] = ip3 & 0xff;
port = (char *)&(info->data_addr.sin_port);
port[0] = port0 & 0xff;
port[1] = port1 & 0xff;
info->data_addr.sin_family = AF_INET;
}
/**************************************************************************
* Function: rtems_ftpd_parse_command *
**************************************************************************
* Description: *
* *
* Here, we parse the commands that have come through the control *
* connection. *
* *
* FIXME: This section is somewhat of a hack. We should have a better *
* way to parse commands. *
* *
* Inputs: *
* *
* char *bufr - Pointer to the buffer which contains the command *
* text. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
rtems_ftpd_parse_command(char *bufr)
{
char fname[255];
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
if (!strncmp("PORT", bufr, 4))
{
rtems_ftpd_send_reply(200, "PORT command successful.");
rtems_ftpd_command_port(&bufr[5]);
}
else if (!strncmp("RETR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
rtems_ftpd_command_retrieve(fname);
}
else if (!strncmp("STOR", bufr, 4))
{
sscanf(&bufr[5], "%254s", fname);
rtems_ftpd_command_store(fname);
}
else if (!strncmp("LIST", bufr, 4))
{
if (bufr[5] == '\n')
{
rtems_ftpd_command_list(".");
}
else
{
sscanf(&bufr[5], "%254s", fname);
rtems_ftpd_command_list(fname);
}
}
else if (!strncmp("USER", bufr, 4))
{
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("SYST", bufr, 4))
{
rtems_ftpd_send_reply(240, "RTEMS");
}
else if (!strncmp("TYPE", bufr, 4))
{
if (bufr[5] == 'I')
{
info->xfer_mode = TYPE_I;
rtems_ftpd_send_reply(200, "Type set to I.");
}
else if (bufr[5] == 'A')
{
info->xfer_mode = TYPE_A;
rtems_ftpd_send_reply(200, "Type set to A.");
}
else
{
info->xfer_mode = TYPE_I;
rtems_ftpd_send_reply(504, "Type not implemented. Set to I.");
}
}
else if (!strncmp("PASS", bufr, 4))
{
rtems_ftpd_send_reply(230, "User logged in.");
}
else if (!strncmp("DELE", bufr, 4))
{
sscanf(&bufr[4], "%254s", fname);
if (unlink(fname) == 0)
{
rtems_ftpd_send_reply(257, "DELE successful.");
}
else
{
rtems_ftpd_send_reply(550, "DELE failed.");
}
}
else if (!strncmp("SITE CHMOD", bufr, 10))
{
int mask;
sscanf(&bufr[11], "%o %254s", &mask, fname);
if (chmod(fname, (mode_t)mask) == 0)
{
rtems_ftpd_send_reply(257, "CHMOD successful.");
}
else
{
rtems_ftpd_send_reply(550, "CHMOD failed.");
}
}
else if (!strncmp("RMD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
if (rmdir(fname) == 0)
{
rtems_ftpd_send_reply(257, "RMD successful.");
}
else
{
rtems_ftpd_send_reply(550, "RMD failed.");
}
}
else if (!strncmp("MKD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
{
rtems_ftpd_send_reply(257, "MKD successful.");
}
else
{
rtems_ftpd_send_reply(550, "MKD failed.");
}
}
else if (!strncmp("CWD", bufr, 3))
{
sscanf(&bufr[4], "%254s", fname);
rtems_ftpd_CWD(fname);
}
else if (!strncmp("PWD", bufr, 3))
{
char *cwd = getcwd(0, 0);
sprintf(bufr, "\"%s\" is the current directory.", cwd);
rtems_ftpd_send_reply(250, bufr);
free(cwd);
}
else
{
rtems_ftpd_send_reply(500, "Unrecognized/unsupported command.");
}
}
/**************************************************************************
* Function: rtems_ftpd_session *
**************************************************************************
* Description: *
* *
* This task is started when the FTP daemon gets a service request *
* from a remote machine. Here, we watch for commands that will *
* come through the "control" connection. These commands are then *
* parsed and executed until the connection is closed, either *
* unintentionally or intentionally with the "QUIT" command. *
* *
* *
* Inputs: *
* *
* rtems_task_argument arg - The daemon task passes the socket *
* which serves as the control connection. *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
static void
rtems_ftpd_session(rtems_task_argument arg)
{
char cmd[256];
rtems_status_code sc;
FTPD_SessionInfo_t *info = NULL;
sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
(rtems_unsigned32 *)&info);
rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE);
/***********************************************************************
* Set initial directory to "/".
**********************************************************************/
strcpy(info->cwd, "/");
info->xfer_mode = TYPE_A;
while (1)
{
if (fgets(cmd, 256, info->ctrl_fp) == NULL)
{
syslog(LOG_INFO, "ftpd: Connection aborted.");
break;
}
if (!strncmp("QUIT", cmd, 4))
{
rtems_ftpd_send_reply(221, "Goodbye.");
break;
}
else
{
rtems_ftpd_parse_command(cmd);
}
}
if (fclose(info->ctrl_fp) != 0)
{
syslog(LOG_ERR, "ftpd: Could not close session.");
}
/* Least we can do is put the CWD back to /. */
chdir("/");
/***********************************************************************
* Free up the allocated SessionInfo struct and exit.
**********************************************************************/
free(info);
sc = rtems_task_delete(RTEMS_SELF);
syslog(LOG_ERR, "ftpd: Task deletion failed: %s",
rtems_status_text(sc));
}
/**************************************************************************
* Function: rtems_ftpd_daemon *
**************************************************************************
* Description: *
* *
* This task runs in the background forever. It waits for service *
* requests on the FTP port (port 21). When a request is received, *
* it opens a new session to handle those requests until the *
* connection is closed. *
* *
* *
* Inputs: *
* *
* none *
* *
* Output: *
* *
* none *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
/* this is not prototyped in strict ansi mode */
FILE *fdopen (int fildes, const char *mode);
static void
rtems_ftpd_daemon()
{
int s;
int s1;
int addrLen;
struct sockaddr_in remoteAddr;
struct sockaddr_in localAddr;
char sessionID;
rtems_task_priority priority;
rtems_status_code sc;
rtems_id tid;
FTPD_SessionInfo_t *info = NULL;
sessionID = 'a';
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
perror("Creating socket");
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(rtems_ftpd_configuration.port);
localAddr.sin_addr.s_addr = INADDR_ANY;
memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero));
if (bind(s, (struct sockaddr *)&localAddr,
sizeof(localAddr)) < 0)
{
perror("Binding control socket");
}
if (listen(s, 2) < 0)
{
perror("Listening on control socket");
}
while (1)
{
/********************************************************************
* Allocate a SessionInfo structure for the session task.
*******************************************************************/
info = (FTPD_SessionInfo_t *)malloc(sizeof(FTPD_SessionInfo_t));
if (info == NULL)
{
syslog(LOG_ERR, "ftpd: Could not allocate session info struct.");
rtems_panic("Malloc fail.");
}
/********************************************************************
* Accept on the socket and start the session task.
*******************************************************************/
addrLen = sizeof(remoteAddr);
s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrLen);
if (s1 < 0)
{
perror("Accepting control connection");
}
rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
sc = rtems_task_create(rtems_build_name('F', 'T', 'P', sessionID),
priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE |
RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
&tid);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not create FTPD session: %s",
rtems_status_text(sc));
}
if (sessionID == 'z')
{
sessionID = 'a';
}
else
{
sessionID++;
}
/********************************************************************
* Send the socket on to the new session.
*******************************************************************/
if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL)
{
syslog(LOG_ERR, "ftpd: fdopen() on socket failed.");
close(s1);
}
else
{
sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
(rtems_unsigned32)info);
sc = rtems_task_start(tid, rtems_ftpd_session, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
rtems_status_text(sc));
}
}
}
}
/**************************************************************************
* Function: rtems_ftpd_start *
**************************************************************************
* Description: *
* *
* Here, we start the FTPD task which waits for FTP requests and *
* services them. This procedure returns to its caller once the *
* task is started. *
* *
* *
* Inputs: *
* *
* rtems_task_priority priority - Priority to assign to this task. *
* *
* Output: *
* *
* int - RTEMS_SUCCESSFUL on successful start of the daemon. *
* *
**************************************************************************
* Change History: *
* 12/01/97 - Creation (JWJ) *
*************************************************************************/
int
rtems_initialize_ftpd()
{
rtems_status_code sc;
rtems_id tid;
if (rtems_ftpd_configuration.port == 0)
{
rtems_ftpd_configuration.port = FTPD_CONTROL_PORT;
}
/***********************************************************************
* Default FTPD priority.
**********************************************************************/
if (rtems_ftpd_configuration.priority == 0)
{
rtems_ftpd_configuration.priority = 40;
}
sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
rtems_ftpd_configuration.priority, 8*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
RTEMS_INTERRUPT_LEVEL(0),
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
&tid);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
sc = rtems_task_start(tid, rtems_ftpd_daemon, 0);
if (sc != RTEMS_SUCCESSFUL)
{
syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s",
rtems_status_text(sc));
return(RTEMS_UNSATISFIED);
}
syslog(LOG_INFO, "ftpd: FTP daemon started.");
return(RTEMS_SUCCESSFUL);
}