Simon:
I sent you my ftpd driver, Please help contribute it ...it uses FatFS as file
system
It still has the problems I mentioned .
Thank you
Vincent Cui
Software Engineer Leader
Mobile: +8613255150315
Tel: +86 21 34612525x6104
Fax: +86 21 34619770
E-Mail: [email protected]<mailto:[email protected]>
Shanghai EnLogic Electric Technology Co., Ltd.
Address: 1104-1106, Building A, No.391, Guiping Road, Xuhui District, Shanghai,
200233
#include <stdarg.h>
#include "lwip/tcp.h"
#include "ff.h"
#include "diskio.h"
#define msg110 "110 MARK %s = %s."
#define msg120 "120 Service ready in nnn minutes."
#define msg125 "125 Data connection already open; transfer starting."
#define msg150 "150 File status okay; about to open data connection."
#define msg150recv "150 Opening BINARY mode data connection for %s (%i bytes)."
#define msg150stor "150 Opening BINARY mode data connection for %s."
#define msg200 "200 Command okay."
#define msg202 "202 Command not implemented, superfluous at this site."
#define msg211 "211 System status, or system help reply."
#define msg212 "212 Directory status."
#define msg213 "213 ."
#define msg214 "214 %s."
#define msg214SYST "214 %s system type."
#define msg220 "220 Enlogic PDU FTP Server ready."
#define msg221 "221 Goodbye."
#define msg225 "225 Data connection open; no transfer in progress."
#define msg226 "226 Closing data connection."
#define msg227 "227 Entering Passive Mode (%i,%i,%i,%i,%i,%i)."
#define msg230 "230 User logged in, proceed."
#define msg250 "250 Requested file action okay, completed."
#define msg257PWD "257 \"%s\" is current directory."
#define msg257 "257 \"%s\" created."
#define msg331 "331 User name okay, need password."
#define msg332 "332 Need account for login."
#define msg350 "350 Requested file action pending further information."
#define msg421 "421 Service not available, closing control connection."
#define msg425 "425 Can't open data connection."
#define msg426 "426 Connection closed; transfer aborted."
#define msg450 "450 Requested file action not taken."
#define msg451 "451 Requested action aborted: local error in processing."
#define msg452 "452 Requested action not taken."
#define msg500 "500 Syntax error, command unrecognized."
#define msg501 "501 Syntax error in parameters or arguments."
#define msg502 "502 Command not implemented."
#define msg503 "503 Bad sequence of commands."
#define msg504 "504 Command not implemented for that parameter."
#define msg530 "530 Not logged in."
#define msg532 "532 Need account for storing files."
#define msg550 "550 Requested action not taken."
#define msg551 "551 Requested action aborted: page type unknown."
#define msg552 "552 Requested file action aborted."
#define msg553 "553 Requested action not taken."
#define FTP_THREAD_PRIO 7
#define SFIFO_MAX_BUFFER_SIZE 256
#define DATACONNECT_BUFFER_SIZE 2048
enum ftpd_state_e {
FTPD_USER, FTPD_PASS, FTPD_IDLE, FTPD_NLST,
FTPD_LIST, FTPD_RETR, FTPD_RNFR, FTPD_STOR,
FTPD_QUIT
};
typedef struct sfifo_t
{
char *buffer;
int size;
int readpos;
int writepos;
} sfifo_t;
struct ftpd_datastate
{
int connected;
FIL *fil;
DIR *dir;
FILINFO *fno;
sfifo_t fifo;
struct tcp_pcb *msgpcb;
struct ftpd_msgstate *msgfs;
};
struct ftpd_msgstate
{
enum ftpd_state_e state;
sfifo_t fifo;
u16_t dataport;
int passive;
char *renamefrom;
struct ip_addr dataip;
struct tcp_pcb *datapcb;
struct tcp_pcb *listenpcb;
struct ftpd_datastate *datafs;
};
struct ftpd_command
{
char *cmd;
void (*func) (const char *arg, struct tcp_pcb * pcb, struct ftpd_msgstate *
fsm);
};
#define SFIFO_SIZEMASK(x) ((x)->size - 1)
#define sfifo_used(x) (((x)->writepos - (x)->readpos) & SFIFO_SIZEMASK(x))
#define sfifo_space(x) ((x)->size - 1 - sfifo_used(x))
void ftpd_init(void);
void Ftp_task(void *pvArg);
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "ftpd.h"
#include "mem.h"
#include "rtc.h"
#include "ff.h"
#include "serial_debug.h"
#include "netconf.h"
int cable_connect = 1;
int datarecv_flag = 0;
static __attribute__ ((aligned (4)))char buffer_x[DATACONNECT_BUFFER_SIZE-1];
struct ftpd_msgstate *fsm;
static FIL sfil;
FIL *fil = &sfil;
static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg,
...);
static const char *month_table[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dez"
};
static void sfifo_flush(sfifo_t *f)
{
f->readpos = 0;
f->writepos = 0;
}
static int32_t sfifo_init(sfifo_t *f, uint32_t size)
{
memset(f, 0, sizeof(sfifo_t));
f->size = size;
sfifo_flush(f);
f->buffer = (void *)mem_malloc(f->size);
if (f->buffer == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG,("mem_malloc error! [%d, %s]\r\n",
__LINE__, __FUNCTION__));
return -1;
}
return 0;
}
static void sfifo_close(sfifo_t *f)
{
if(f->buffer)
{
mem_free(f->buffer);
}
sfifo_flush(f);
}
static int32_t sfifo_write(sfifo_t *f, const void *_buf, uint32_t len)
{
int32_t total = 0;
uint32_t i = 0;
const char *buf = (const char *)_buf;
if(!f->buffer)
{
return -1;
}
total = sfifo_space(f);
if(len > total)
{
len = total;
}
else
{
total = len;
}
i = f->writepos;
if(i + len > f->size)
{
memcpy(f->buffer + i, buf, f->size - i);
buf += f->size - i;
len -= f->size - i;
i = 0;
}
memcpy(f->buffer + i, buf, len);
f->writepos = i + len;
return total;
}
static void ftpd_dataerr(void *arg, err_t err)
{
struct ftpd_datastate *fsd = arg;
/*
if (fsd != NULL)
{
sfifo_close(&fsd->fifo);
mem_free(fsd);
}
*/
if (fsm->datafs != NULL)
{
sfifo_close(&fsm->datafs->fifo);
mem_free(fsm->datafs);
fsm->datafs = NULL;
}
if (fsm->listenpcb)
{
tcp_close(fsm->listenpcb);
}
fsd->msgfs->state = FTPD_IDLE;
}
static void ftpd_dataclose(struct tcp_pcb *pcb, struct ftpd_datastate *fsd)
{
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
fsd->msgfs->datafs = NULL;
sfifo_close(&fsd->fifo);
mem_free(fsd);
tcp_close(pcb);
if (fsm->listenpcb)
{
tcp_close(fsm->listenpcb);
}
}
static void send_data(struct tcp_pcb *pcb, struct ftpd_datastate *fsd)
{
err_t err;
u16_t len;
int i;
if (sfifo_used(&fsd->fifo) > 0)
{
if (tcp_sndbuf(pcb) < sfifo_used(&fsd->fifo))
{
len = tcp_sndbuf(pcb);
}
else
{
len = (u16_t)sfifo_used(&fsd->fifo);
}
i = fsd->fifo.readpos;
if ((i + len) > fsd->fifo.size)
{
err = tcp_write(pcb, fsd->fifo.buffer + i, (u16_t)(fsd->fifo.size -
i), 1);
if (err != ERR_OK)
{
return;
}
len -= fsd->fifo.size - i;
fsd->fifo.readpos = 0;
i = 0;
}
err = tcp_write(pcb, fsd->fifo.buffer + i, len, 1);
if (err != ERR_OK)
{
return;
}
fsd->fifo.readpos += len;
}
}
static void send_file(struct ftpd_datastate *fsd, struct tcp_pcb *pcb)
{
FRESULT rc;
if (!fsd->connected)
{
return;
}
if (fsd->fil)
{
UINT len;
if (sfifo_space(&fsd->fifo) < (DATACONNECT_BUFFER_SIZE - 2))
{
send_data(pcb, fsd);
return;
}
rc = f_read(fsd->fil, buffer_x, sizeof (buffer_x), &len);
if (rc || (len == 0))
{
f_close(fsd->fil);
fsd->fil = NULL;
return;
}
sfifo_write(&fsd->fifo, buffer_x, len);
send_data(pcb, fsd);
if (sfifo_used(&fsd->fifo) < 1024)
{
send_data(pcb, fsd);
return;
}
rc = f_read(fsd->fil, buffer_x, sfifo_space(&fsd->fifo), &len);
if (rc || (len == 0))
{
f_close(fsd->fil);
fsd->fil = NULL;
return;
}
sfifo_write(&fsd->fifo, buffer_x, len);
}
else
{
struct ftpd_msgstate *fsm;
struct tcp_pcb *msgpcb;
if (sfifo_used(&fsd->fifo) > 0)
{
send_data(pcb, fsd);
return;
}
fsm = fsd->msgfs;
msgpcb = fsd->msgpcb;
f_close(fsd->fil);
fsd->fil = NULL;
ftpd_dataclose(pcb, fsd);
fsm->datapcb = NULL;
fsm->datafs = NULL;
fsm->state = FTPD_IDLE;
send_msg(msgpcb, fsm, msg226);
}
return;
}
static void send_next_directory(struct ftpd_datastate *fsd, struct tcp_pcb
*pcb, int shortlist)
{
FRESULT rc;
int len;
char buffer_y[128];
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateTypeDef RTC_DateStructure;
while (1)
{
if (fsd->fno == NULL)
{
fsd->fno = mem_malloc(sizeof(FILINFO));
if (fsd->fno == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc
error! [%d, %s]\r\n", __LINE__, __FUNCTION__));
return;
}
rc = f_readdir(fsd->dir, fsd->fno);
if (rc || !fsd->fno->fname[0])
{
return; /* Error or end of dir */
}
if (shortlist)
{
len = sprintf(buffer_y, "%8lu %s\r\n",
fsd->fno->fsize, fsd->fno->fname);
sfifo_write(&fsd->fifo, buffer_y, len);
send_data(pcb, fsd);
mem_free(fsd->fno);
fsd->fno = NULL;
}
else
{
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
len = sprintf(buffer_y, "-rw-rw-rw- 1 enlogic
ftp %11ld %s %02i %02i:%02i %s\r\n", fsd->fno->fsize,
month_table[RTC_DateStructure.RTC_Month], RTC_DateStructure.RTC_WeekDay,
RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, fsd->fno->fname);
if (fsd->fno->fattrib & AM_DIR)
{
buffer_y[0] = 'd';
}
sfifo_write(&fsd->fifo, buffer_y, len);
send_data(pcb, fsd);
mem_free(fsd->fno);
fsd->fno = NULL;
}
}
else
{
struct ftpd_msgstate *fsm;
struct tcp_pcb *msgpcb;
if (sfifo_used(&fsd->fifo) > 0)
{
send_data(pcb, fsd);
return;
}
fsm = fsd->msgfs;
msgpcb = fsd->msgpcb;
mem_free(fsd->fno);
fsd->dir = NULL;
fsd->fno = NULL;
ftpd_dataclose(pcb, fsd);
fsm->datapcb = NULL;
fsm->datafs = NULL;
fsm->state = FTPD_IDLE;
send_msg(msgpcb, fsm, msg226);
return;
}
}
}
static err_t ftpd_datasent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct ftpd_datastate *fsd = arg;
switch (fsd->msgfs->state)
{
case FTPD_LIST:
send_next_directory(fsd, pcb, 0);
break;
case FTPD_NLST:
send_next_directory(fsd, pcb, 1);
break;
case FTPD_RETR:
send_file(fsd, pcb);
break;
default:
break;
}
return ERR_OK;
}
static err_t ftpd_datarecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p,
err_t err)
{
struct ftpd_datastate *fsd = arg;
if (err == ERR_OK && p != NULL)
{
struct pbuf *q;
u16_t tot_len = 0;
for (q = p; q != NULL; q = q->next)
{
UINT len;
f_write(fsd->fil, q->payload, q->len, &len);
tot_len += len;
if (len != q->len)
break;
}
tcp_recved(pcb, tot_len);
pbuf_free(p);
datarecv_flag = 1;
}
if (err == ERR_OK && p == NULL)
{
struct ftpd_msgstate *fsm;
struct tcp_pcb *msgpcb;
fsm = fsd->msgfs;
msgpcb = fsd->msgpcb;
f_close(fsd->fil);
fsd->fil = NULL;
ftpd_dataclose(pcb, fsd);
fsm->datapcb = NULL;
fsm->datafs = NULL;
fsm->state = FTPD_IDLE;
send_msg(msgpcb, fsm, msg226);
datarecv_flag = 0;
}
return ERR_OK;
}
static err_t ftpd_dataconnected(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct ftpd_datastate *fsd = arg;
fsd->msgfs->datapcb = pcb;
fsd->connected = 1;
tcp_recv(pcb, ftpd_datarecv);
tcp_sent(pcb, ftpd_datasent);
tcp_err(pcb, ftpd_dataerr);
switch (fsd->msgfs->state)
{
case FTPD_LIST:
send_next_directory(fsd, pcb, 0);
break;
case FTPD_NLST:
send_next_directory(fsd, pcb, 1);
break;
case FTPD_RETR:
send_file(fsd, pcb);
break;
default:
break;
}
return ERR_OK;
}
static err_t ftpd_dataaccept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct ftpd_datastate *fsd = arg;
fsd->msgfs->datapcb = pcb;
fsd->connected = 1;
tcp_recv(pcb, ftpd_datarecv);
tcp_sent(pcb, ftpd_datasent);
tcp_err(pcb, ftpd_dataerr);
switch (fsd->msgfs->state)
{
case FTPD_LIST:
send_next_directory(fsd, pcb, 0);
break;
case FTPD_NLST:
send_next_directory(fsd, pcb, 1);
break;
case FTPD_RETR:
send_file(fsd, pcb);
break;
default:
break;
}
return ERR_OK;
}
static int open_dataconnection(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
{
if (fsm->passive)
{
fsm->passive = 0;
return 0;
}
if (fsm->datafs != NULL)
{
mem_free(fsm->datafs);
fsm->datafs = NULL;
}
fsm->datafs = mem_malloc(sizeof(struct ftpd_datastate));
if (fsm->datafs == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d,
%s]\r\n", __LINE__, __FUNCTION__));
send_msg(pcb, fsm, msg451);
return 1;
}
memset(fsm->datafs, 0, sizeof(struct ftpd_datastate));
fsm->datafs->msgfs = fsm;
fsm->datafs->msgpcb = pcb;
if (sfifo_init(&fsm->datafs->fifo, DATACONNECT_BUFFER_SIZE) < 0)
{
return -1;
}
fsm->datapcb = tcp_new();
tcp_bind(fsm->datapcb, &pcb->local_ip, 20);
tcp_arg(fsm->datapcb, fsm->datafs);
if ( ERR_OK != tcp_connect(fsm->datapcb, &fsm->dataip, fsm->dataport,
ftpd_dataconnected))
{
return -1;
}
return 0;
}
static void cmd_user(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg331);
fsm->state = FTPD_PASS;
}
static void cmd_port(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
int nr;
unsigned pHi, pLo;
unsigned ip[4];
nr = sscanf(arg, "%u,%u,%u,%u,%u,%u", &(ip[0]), &(ip[1]), &(ip[2]),
&(ip[3]), &pHi, &pLo);
if (nr != 6)
{
send_msg(pcb, fsm, msg501);
}
else
{
IP4_ADDR(&fsm->dataip, (u8_t) ip[0], (u8_t) ip[1], (u8_t)
ip[2], (u8_t) ip[3]);
fsm->dataport = ((u32_t) pHi << 8) + (u32_t)pLo;
send_msg(pcb, fsm, msg200);
}
}
static void cmd_quit(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg221);
fsm->state = FTPD_QUIT;
}
static void cmd_pwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
char path[32] = {0};
char *ptr = NULL;
if (!f_getcwd(path, sizeof(path)))
{
ptr = strchr(path, ':');
ptr ++;
send_msg(pcb, fsm, msg257PWD, ptr);
}
}
static void cmd_list_common(const char *arg, struct tcp_pcb *pcb, struct
ftpd_msgstate *fsm, int shortlist)
{
FRESULT rc;
DIR *dir;
dir = mem_malloc(sizeof(DIR));
if (dir == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d,
%s]\r\n", __LINE__, __FUNCTION__));
return;
}
rc = f_opendir(dir, "");
if (rc)
{
return;
}
if (open_dataconnection(pcb, fsm) != 0)
{
mem_free(dir);
dir = NULL;
return;
}
fsm->datafs->dir = dir;
fsm->datafs->fno = NULL;
if (shortlist != 0)
{
fsm->state = FTPD_NLST;
}
else
{
fsm->state = FTPD_LIST;
}
send_msg(pcb, fsm, msg150);
}
static void cmd_nlst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
cmd_list_common(arg, pcb, fsm, 1);
}
static void cmd_list(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
cmd_list_common(arg, pcb, fsm, 0);
}
static void cmd_syst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg214SYST, "Windows NT");
}
static void cmd_type(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg200);
}
static void cmd_mode(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg502);
}
static void cmd_rnfr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
if (arg == NULL)
{
send_msg(pcb, fsm, msg501);
return;
}
if (*arg == '\0')
{
send_msg(pcb, fsm, msg501);
return;
}
if (fsm->renamefrom)
{
mem_free(fsm->renamefrom);
}
fsm->renamefrom = mem_malloc(strlen(arg) + 1);
if (fsm->renamefrom == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG,("mem_malloc error! [%d, %s]\r\n",
__LINE__, __FUNCTION__));
send_msg(pcb, fsm, msg451);
return;
}
strcpy(fsm->renamefrom, arg);
fsm->state = FTPD_RNFR;
send_msg(pcb, fsm, msg350);
}
static void cmd_rnto(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
if (fsm->state != FTPD_RNFR)
{
send_msg(pcb, fsm, msg503);
return;
}
fsm->state = FTPD_IDLE;
if (arg == NULL)
{
send_msg(pcb, fsm, msg501);
return;
}
if (*arg == '\0')
{
send_msg(pcb, fsm, msg501);
return;
}
if (!f_rename(fsm->renamefrom, arg))
{
send_msg(pcb, fsm, msg250);
}
else
{
send_msg(pcb, fsm, msg450);
}
}
static void cmd_mkd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
if (arg == NULL)
{
send_msg(pcb, fsm, msg501);
return;
}
if (*arg == '\0')
{
send_msg(pcb, fsm, msg501);
return;
}
if (!f_mkdir(arg))
{
send_msg(pcb, fsm, msg257, arg);
}
else
{
send_msg(pcb, fsm, msg550);
}
}
static void cmd_pass(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg230);
f_chdir("/");
fsm->state = FTPD_IDLE;
}
static void cmd_cwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
if (!f_chdir(arg))
{
send_msg(pcb, fsm, msg250);
}
else
{
send_msg(pcb, fsm, msg550);
}
}
static void cmd_cdup(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
if (!f_chdir(arg))
{
send_msg(pcb, fsm, msg250);
}
else
{
send_msg(pcb, fsm, msg550);
}
}
static void cmd_retr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
FRESULT rc;
rc = f_open(fil, arg, FA_READ);
if (rc)
{
send_msg(pcb, fsm, msg550);
return;
}
send_msg(pcb, fsm, msg150recv, arg, strlen(arg));
if (open_dataconnection(pcb, fsm) != 0)
{
f_close(fil);
return;
}
fsm->datafs->fil = fil;
fsm->state = FTPD_RETR;
}
static void cmd_stor(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
FRESULT rc;
rc = f_open(fil, arg, FA_WRITE | FA_CREATE_ALWAYS);
if (rc)
{
send_msg(pcb, fsm, msg550);
return;
}
send_msg(pcb, fsm, msg150stor, arg);
if (open_dataconnection(pcb, fsm) != 0)
{
f_close(fil);
return;
}
fsm->datafs->fil = fil;
fsm->state = FTPD_STOR;
}
static void cmd_size(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg213);
}
static void cmd_appe(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg213);
}
static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
static u16_t port = 4096;
static u16_t start_port = 4096;
struct tcp_pcb *temppcb;
if (fsm->datafs != NULL)
{
mem_free(fsm->datafs);
fsm->datafs = NULL;
}
fsm->datafs = mem_malloc(sizeof(struct ftpd_datastate));
if (fsm->datafs == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d,
%s]\r\n", __LINE__, __FUNCTION__));
send_msg(pcb, fsm, msg451);
return;
}
memset(fsm->datafs, 0, sizeof(struct ftpd_datastate));
if (fsm->datapcb != NULL)
{
tcp_close(fsm->datapcb);
}
fsm->datapcb = tcp_new();
if (!fsm->datapcb)
{
mem_free(fsm->datafs);
send_msg(pcb, fsm, msg451);
return;
}
if (sfifo_init(&fsm->datafs->fifo, DATACONNECT_BUFFER_SIZE) < 0)
{
return ;
}
start_port = port;
while (1)
{
err_t err;
if(++port > 0x4fff)
{
port = 4096;
}
fsm->dataport = port;
err = tcp_bind(fsm->datapcb, &pcb->local_ip, fsm->dataport);
if (err == ERR_OK)
{
break;
}
if (start_port == port)
{
err = ERR_CLSD;
}
if (err == ERR_USE)
{
continue;
}
if (err != ERR_OK)
{
ftpd_dataclose(fsm->datapcb, fsm->datafs);
fsm->datapcb = NULL;
fsm->datafs = NULL;
return;
}
}
temppcb = tcp_listen(fsm->datapcb);
if (!temppcb)
{
printf(" tmppcb fails \r\n");
ftpd_dataclose(fsm->datapcb, fsm->datafs);
fsm->datapcb = NULL;
fsm->datafs = NULL;
return;
}
fsm->listenpcb = temppcb;
fsm->passive = 1;
fsm->datafs->connected = 0;
fsm->datafs->msgfs = fsm;
fsm->datafs->msgpcb = pcb;
tcp_arg(fsm->listenpcb, fsm->datafs);
tcp_accept(fsm->listenpcb, ftpd_dataaccept);
send_msg(pcb, fsm, msg227, ip4_addr1(&pcb->local_ip),
ip4_addr2(&pcb->local_ip), ip4_addr3(&pcb->local_ip),
ip4_addr4(&pcb->local_ip), (fsm->dataport >> 8) & 0xff, (fsm->dataport) &
0xff);
}
static void cmd_abrt(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
tcp_arg(fsm->datapcb, NULL);
tcp_sent(fsm->datapcb, NULL);
tcp_recv(fsm->datapcb, NULL);
tcp_abort(pcb);
fsm->state = FTPD_IDLE;
}
static void cmd_dele(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
FILINFO finfo;
if (arg == NULL)
{
send_msg(pcb, fsm, msg501);
return;
}
if (*arg == '\0')
{
send_msg(pcb, fsm, msg501);
return;
}
if (f_stat(arg, &finfo))
{
send_msg(pcb, fsm, msg550);
return;
}
if (!f_unlink(arg))
{
send_msg(pcb, fsm, msg250);
}
else
{
send_msg(pcb, fsm, msg550);
}
}
static void cmd_rmd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
cmd_dele(arg, pcb, fsm);
}
static void cmd_noop(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate
*fsm)
{
send_msg(pcb, fsm, msg200);
}
static struct ftpd_command ftpd_commands[] = {
"USER", cmd_user,
"PASS", cmd_pass,
"PORT", cmd_port,
"QUIT", cmd_quit,
"BYE", cmd_quit,
"CWD", cmd_cwd,
"CDUP", cmd_cdup,
"PWD", cmd_pwd,
"XPWD", cmd_pwd,
"NLST", cmd_nlst,
"LIST", cmd_list,
"RETR", cmd_retr,
"STOR", cmd_stor,
"NOOP", cmd_noop,
"SYST", cmd_syst,
"ABOR", cmd_abrt,
"TYPE", cmd_type,
"MODE", cmd_mode,
"RNFR", cmd_rnfr,
"RNTO", cmd_rnto,
"MKD", cmd_mkd,
"XMKD", cmd_mkd,
"RMD", cmd_rmd,
"XRMD", cmd_rmd,
"DELE", cmd_dele,
"PASV", cmd_pasv,
"SIZE", cmd_size,
"APPE", cmd_appe,
NULL
};
static void send_msgdata(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
{
err_t err;
u16_t len;
if (sfifo_used(&fsm->fifo) > 0)
{
int i;
if (tcp_sndbuf(pcb) < sfifo_used(&fsm->fifo))
{
len = tcp_sndbuf(pcb);
} else
{
len = (u16_t) sfifo_used(&fsm->fifo);
}
i = fsm->fifo.readpos;
if ((i + len) > fsm->fifo.size)
{
err = tcp_write(pcb, fsm->fifo.buffer + i, (u16_t)(fsm->fifo.size -
i), 1);
if (err != ERR_OK)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("send_msgdata: error
writing!\n"));
return;
}
len -= fsm->fifo.size - i;
fsm->fifo.readpos = 0;
i = 0;
}
err = tcp_write(pcb, fsm->fifo.buffer + i, len, 1);
if (err != ERR_OK)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("send_msgdata: error writing!\n"));
return;
}
fsm->fifo.readpos += len;
}
}
static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg,
...)
{
va_list arg;
char buffer[SFIFO_MAX_BUFFER_SIZE];
int len;
va_start(arg, msg);
vsprintf(buffer, msg, arg);
va_end(arg);
strcat(buffer, "\r\n");
len = strlen(buffer);
if (sfifo_space(&fsm->fifo) < len)
{
return;
}
sfifo_write(&fsm->fifo, buffer, len);
send_msgdata(pcb, fsm);
}
static void ftpd_msgerr(void *arg, err_t err)
{
struct ftpd_msgstate *fsm = arg;
if (fsm == NULL)
{
return;
}
if (fsm->datafs)
{
ftpd_dataclose(fsm->datapcb, fsm->datafs);
}
sfifo_close(&fsm->fifo);
mem_free(fsm);
}
static void ftpd_msgclose(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
{
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
if (fsm->datafs)
{
ftpd_dataclose(fsm->datapcb, fsm->datafs);
}
sfifo_close(&fsm->fifo);
mem_free(fsm);
tcp_arg(pcb, NULL);
tcp_close(pcb);
}
static err_t ftpd_msgsent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct ftpd_msgstate *fsm = arg;
if (pcb->state > ESTABLISHED)
{
return ERR_OK;
}
if ((sfifo_used(&fsm->fifo) == 0) && (fsm->state == FTPD_QUIT))
{
ftpd_msgclose(pcb, fsm);
}
send_msgdata(pcb, fsm);
return ERR_OK;
}
static err_t ftpd_msgrecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t
err)
{
char *text = NULL;
struct ftpd_msgstate *fsm = arg;
if (err == ERR_OK && p != NULL)
{
tcp_recved(pcb, p->tot_len);
text = mem_malloc(p->tot_len + 1);
if (text)
{
char cmd[5];
struct pbuf *q;
char *pt = text;
struct ftpd_command *ftpd_cmd;
for (q = p; q != NULL; q = q->next)
{
memcpy(pt, q->payload, q->len);
pt += q->len;
}
*pt = '\0';
pt = &text[strlen(text) - 1];
while (((*pt == '\r') || (*pt == '\n')) && pt >= text)
{
*pt-- = '\0';
}
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("query: %s \r\n", text));
if (!strncmp(text, "CWD", 3) || !strncmp(text, "MKD",
3) || !strncmp(text, "RMD", 3))
{
strncpy(cmd, text, 3);
for (pt = cmd; (pt < &cmd[3]); pt++)
*pt = toupper(*pt);
} else
{
strncpy(cmd, text, 4);
for (pt = cmd; (pt < &cmd[4]); pt++)
*pt = toupper(*pt);
}
*pt = '\0';
for (ftpd_cmd = ftpd_commands; ftpd_cmd->cmd != NULL;
ftpd_cmd++)
{
if (!strcmp(ftpd_cmd->cmd, cmd))
{
break;
}
}
if (strlen(text) < (strlen(cmd) + 1))
{
pt = "";
}
else
{
pt = &text[strlen(cmd) + 1];
}
if (ftpd_cmd->func)
{
ftpd_cmd->func(pt, pcb, fsm);
}
else
{
send_msg(pcb, fsm, msg502);
}
mem_free(text);
}
pbuf_free(p);
}
return ERR_OK;
}
static err_t ftpd_msgpoll(void *arg, struct tcp_pcb *pcb)
{
struct ftpd_msgstate *fsm = arg;
if (fsm == NULL)
{
return ERR_OK;
}
if (fsm->datafs)
{
if (fsm->datafs->connected)
{
switch (fsm->state)
{
case FTPD_LIST:
send_next_directory(fsm->datafs,
fsm->datapcb, 0);
break;
case FTPD_NLST:
send_next_directory(fsm->datafs,
fsm->datapcb, 1);
break;
case FTPD_RETR:
send_file(fsm->datafs, fsm->datapcb);
break;
default:
break;
}
}
}
if (cable_connect == 0 && datarecv_flag == 1)
{
ftpd_msgclose(pcb, fsm);
/*
if (fsm->listenpcb)
{
tcp_close(fsm->listenpcb);
}
*/
}
return ERR_OK;
}
static err_t ftpd_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err)
{
fsm = mem_malloc(sizeof(struct ftpd_msgstate));
if (fsm == NULL)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("ftpd_msgaccept: Out of memory \r\n"));
return ERR_MEM;
}
memset(fsm, 0, sizeof(struct ftpd_msgstate));
if (sfifo_init(&fsm->fifo, SFIFO_MAX_BUFFER_SIZE) < 0)
{
PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("ftpd msgaccept: Out of memory
\r\n"));
return ERR_MEM;
}
fsm->state = FTPD_IDLE;
tcp_arg(pcb, fsm);
tcp_recv(pcb, ftpd_msgrecv);
tcp_sent(pcb, ftpd_msgsent);
tcp_err(pcb, ftpd_msgerr);
tcp_poll(pcb, ftpd_msgpoll, 1);
send_msg(pcb, fsm, msg220);
return ERR_OK;
}
static void ftpd_init(void)
{
struct tcp_pcb *pcb;
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 21);
pcb = tcp_listen(pcb);
tcp_accept(pcb, ftpd_msgaccept);
for (;;)
{
vTaskDelay(250);
}
}
void Ftp_task(void *pvArg)
{
LwIP_DHCP_wait();
ftpd_init();
}
_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users