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

Reply via email to