FTP Server porting using FreeRTOS on Atmel

gupta123 wrote on Friday, June 08, 2012:

Dear Rachid

Can you gide me I am using FTP_server.c &FTP_Server.h wants Port FTP Server on Atmel Microcontroller using FreeRTOS.I am Facing issue for compliation of netconn_api related for Atmel microntroller at91sam9xe-ek using SDCard for tranfer file using FTP.

/* ---------------- FreeRTOS includes ------------------- */
#include “FreeRTOS.h”
#include “task.h”
#include “semphr.h”

/* ---------------- lwIP includes ---------------------- */
#include “api.h”

/* ---------------- Project includes -------------------- */
#include “SD.h”         /* SD Card Driver (SPI mode) */
#include “FAT.h”

/* ---------------- Project includes -------------------- */
#include “ftp_server.h”
#include “utilities.h”

#define FTP_USERNAME          “user”
#define FTP_PASSWORD          “Freescale123”

/*Handle SD card*/
static FATHandler *SD_FTP_Handle;

/*Read Buffer for App*/ 
static UINT8 *SDbuffer;

#define FTP_MUTEX_ENTER   xSemaphoreTake((xSemaphoreHandle)SD_FTP_Handle->FAT_Mutex, portMAX_DELAY);
#define FTP_MUTEX_EXIT    xSemaphoreGive((xSemaphoreHandle)SD_FTP_Handle->FAT_Mutex);

/*FSL:sprintf prototype*/
INT
sprintf(CHAR *, const CHAR *, … );

/********************Private Functions ***************************************/

/**
* FTP Server Main Control Socket Parser: requests and responses
*  Available requests: USER, PASS, PORT, QUIT
*
* @param connection descriptor
* @param buffer to hold FTP requests
* @return none
*/
static uint8
vFTPConnection(struct netconn *connfd, uint8 *alloc_rq)
{
  //uint8 temp_data;
  uint8 correct_login = FALSE;

  /*send FTP server first RESPONSE*/
  //****RESPONSE OK CONNECTED
  netconn_write(connfd,FTP_WELCOME_RESPONSE,str_len(FTP_WELCOME_RESPONSE),NULL);
 
  do
  {
    /*if reception is OK: wait for REQUEST from client*/
    netconn_rcv_req((void *)connfd, alloc_rq, NULL,NULL);
    if(connfd->err != ERR_OK)
    {
      /*session closed by client*/
      break;
    }
   
    /*authentication required*/          
    if( correct_login == TRUE)//already logged in
    {
       /*PORT request*/
       if( strstr(alloc_rq,FTP_PORT_REQUEST) != NULL )
       {
          FTP_DataFlowControl(connfd,&alloc_rq);
       }
       /*DELETE request*/
       else if( strstr(alloc_rq,FTP_DELE_REQUEST) != NULL )
       {
          if (FILE_DELETED == FAT_FileDelete(SD_FTP_Handle,SDbuffer,(uint8 *)strupr(&alloc_rq)) )
          {
             //****RESPONSE: OK
             netconn_write(connfd,FTP_DELE_OK_RESPONSE,str_len(FTP_DELE_OK_RESPONSE),NULL);           
          }
          else
          {
             //****RESPONSE: FAILED
             netconn_write(connfd,FTP_WRITE_FAIL_RESPONSE,str_len(FTP_WRITE_FAIL_RESPONSE),NULL);            
          }
       }
       /*UNIMPLEMENTED request*/
       else
       {
          if( !FTP_QUIT_OR_WRONG_REQUEST(connfd,alloc_rq) )
          {
             break;/*QUIT command*/
          }
       }
    }
    else//not logged in
    {
       if( strstr(alloc_rq,FTP_USER_REQUEST) != NULL )
       {         
          /*authentication process: username matchs exactly?*/
          if( !strncmp(&alloc_rq,FTP_USERNAME,str_len(FTP_USERNAME)) )
          {
              //*****RESPONSE USER OK
              netconn_write(connfd,FTP_USER_RESPONSE,str_len(FTP_USER_RESPONSE),NULL);
             
              /*if reception is OK: wait for REQUEST from client*/
              netconn_rcv_req((void *)connfd, alloc_rq, NULL, NULL);
              if(connfd->err != ERR_OK)
              {
                 /*session closed by client*/
                 break;
              }
             
              if( strstr(alloc_rq,FTP_PASS_REQUEST) != NULL )
              {
                  /*authentication process: password matchs exactly?*/
                  if( !strncmp(&alloc_rq,FTP_PASSWORD,str_len(FTP_PASSWORD)) )
                  {
                    //***RESPONSE: PASSWORD OK
                    netconn_write(connfd,FTP_PASS_OK_RESPONSE,str_len(FTP_PASS_OK_RESPONSE),NULL);
                   
                    correct_login = TRUE;
                  }
                  else
                  {
                    //***RESPONSE: PASSWORD FAILED
                    netconn_write(connfd,FTP_PASS_FAIL_RESPONSE,str_len(FTP_PASS_FAIL_RESPONSE),NULL);
                  }
              }
              else
              {
                  //***RESPONSE: EXPECTING PASS request
                  netconn_write(connfd,FTP_BAD_SEQUENCE_RESPONSE,str_len(FTP_BAD_SEQUENCE_RESPONSE),NULL);
              }
          }
          else
          {
              //***RESPONSE USER FAILED
              netconn_write(connfd,FTP_PASS_FAIL_RESPONSE,str_len(FTP_PASS_FAIL_RESPONSE),NULL);
          }
       }
       else
       {
          if( !FTP_QUIT_OR_WRONG_REQUEST(connfd,alloc_rq) )
          {
             break;/*QUIT command*/
          }
       }
    }
  }while(1);     

ftp_tcp_exit_low:
  /*client closing the session*/
  netconn_close(connfd);
  netconn_delete(connfd);
 
  /*close the session!!*/

  return 1;/*default close value*/
}

/**
* Closes or Leave session depending on client request
*
* @param connection descriptor
* @param buffer space
* @return 0 keep session, otherwise session needs to be closed
*/
uint8
FTP_QUIT_OR_WRONG_REQUEST(struct netconn *connfd, uint8 *alloc_rq)
{
   if( strstr(alloc_rq,FTP_QUIT_REQUEST) != NULL )
   {
      //****RESPONSE CLOSING SESSION: BYE
      netconn_write(connfd,FTP_QUIT_RESPONSE,str_len(FTP_QUIT_RESPONSE),NULL);
      return 1;/*close session*/
   }
   else
   {
      //****UNKNOWN REQUEST
      netconn_write(connfd,FTP_UNKNOWN_RESPONSE,str_len(FTP_UNKNOWN_RESPONSE),NULL);
      return 0;/*keep session*/
   } 
}

/**
* Open data socket: ftp server connects to client.
*
* @param ip address to connect to
* @param tcp port to connect to
* @return connection descriptor, if NULL error, other OK.
*/
struct netconn *
FTP_OpenDataPort(struct ip_addr *add, uint16 port)
{
  /*START:open specific port requested by PORT*/
  /* Create a new TCP connection handle. */
  struct netconn *conn_data;
 
  /*create data port*/
  if( (conn_data = netconn_new(NETCONN_TCP)) == NULL )
  {
     return NULL;/*error*/
  }
  /*wait until it’s linked to server*/
  if( netconn_connect(conn_data,add,port) != ERR_OK )
  {
     return NULL;/*error*/
  }   
  /*set timeout for this connection*/
  //netconn_set_timeout((void *)conn_data,4000/*timeout*/);
 
  /*END*/
  return conn_data; 
}

/**
* Close data socket
*
* @param connection descriptor
* @return 0 if connection was closed
*/
static uint8
FTP_CloseDataPort(struct netconn *conn_data)
{
  /*delete TCP connection*/
  netconn_close(conn_data);
  netconn_delete(conn_data); 
 
  return 0;
}

/**
* FTP Server Main Data Socket Parser: requests and responses
*  Available requests: NLST, RTR, STOR
*
* @param connection descriptor
* @param string containing data socket port number and address
* @return none
*/
static uint8
FTP_DataFlowControl(struct netconn *connfd, uint8 *alloc_rq)
{
    /*netconn describing DATA flow path*/
    struct netconn *conn_data;
    /*FTP client IP address*/
    T32_8 ip_address;
    T16_8 ftp_port;   
    /*temporal pointers*/
    CHAR *end;
    /*temporal counter*/
    CHAR i;

    /*****START: get PORT information: parsing*/
    //Get IP: four parts
    for(i=0;i<sizeof(ip_address);i++)
    {
       end = (CHAR *)strchr((const CHAR *)alloc_rq,’,’);       
       ip_address.bytes = (uint8)strtoul(alloc_rq,(char **)&end,10);
       alloc_rq = (uint8 *)end + 1;     
    }
    //Get FTP Port:first part
    end = (CHAR *)strchr((const CHAR *)alloc_rq,’,’);       
    ftp_port.u8 = (uint8)strtoul(alloc_rq,(char **)&end,10);
    alloc_rq = (uint8 *)end + 1;
    //Get FTP Port:second part
    end = (CHAR *)strchr((const CHAR *)alloc_rq,’\r’);       
    ftp_port.u8 = (uint8)strtoul(alloc_rq,(char **)&end,10);
    /*****END**********************************/
    
    //*****RESPONSE: OPEN PORT
    netconn_write(connfd,FTP_PORT_OK_RESPONSE,str_len(FTP_PORT_OK_RESPONSE),NULL);
   
    /*if reception is OK: wait for REQUEST from client from CONTROL port*/
    netconn_rcv_req((void *)connfd, alloc_rq, NULL, NULL);
    if(connfd->err != ERR_OK)
    {
       /*session closed by client*/
       return 1;/*FAIL*/
    }
   
    /*NLST*/
    if( strstr(alloc_rq,FTP_NLST_REQUEST) != NULL )
    {
      if( (conn_data = FTP_OpenDataPort((struct ip_addr *)&(ip_address.lword),ftp_port.u16)) != NULL )
      {
        //****Response Sending
        netconn_write(connfd,FTP_NLST_OK_RESPONSE,str_len(FTP_NLST_OK_RESPONSE),NULL);
       
        //Send the file list
        FTP_Read_List_Of_Files(conn_data);
       
        //Start Closing Data Stream
        FTP_CloseDataPort(conn_data);
       
        //****RESPONSE: OK
        netconn_write(connfd,FTP_TRANSFER_OK_RESPONSE,str_len(FTP_TRANSFER_OK_RESPONSE),NULL);
      }
      else
      {
        //****RESPONSE PORT cant be opened!!
        netconn_write(connfd,FTP_DATA_PORT_FAILED,str_len(FTP_DATA_PORT_FAILED),NULL);
       
        return 1;/*FAIL*/       
      }
    }
    /*READ*/
    else if( strstr(alloc_rq,FTP_RETR_REQUEST) != NULL )   
    {
      if( !FTP_Read_Is_Possible(&alloc_rq) )
      {
        if( (conn_data = FTP_OpenDataPort((struct ip_addr *)&(ip_address.lword),ftp_port.u16)) != NULL )
        {
          //****Response Sending
          netconn_write(connfd,FTP_RETR_OK_RESPONSE,str_len(FTP_RETR_OK_RESPONSE),NULL);
         
          //send info
          FTP_Read_File(conn_data);
         
          //Start Closing Data Stream
          FTP_CloseDataPort(conn_data);
         
          //****RESPONSE: OK
          netconn_write(connfd,FTP_TRANSFER_OK_RESPONSE,str_len(FTP_TRANSFER_OK_RESPONSE),NULL);
        }
        else
        {
          return 1;
        }
      }
      else
      {
        //****RESPONSE: DUPLICATION FILE NAME
        netconn_write(connfd,FTP_WRITE_FAIL_RESPONSE,str_len(FTP_WRITE_FAIL_RESPONSE),NULL);
      }
    }
    /*WRITE*/
    else if( strstr(alloc_rq,FTP_STOR_REQUEST) != NULL )
    {
      if( !FTP_Does_File_Exist(&alloc_rq) )
      {
         //****RESPONSE: FILE ALREADY EXISTS
         netconn_write(connfd,FTP_WRITE_FAIL_RESPONSE,str_len(FTP_WRITE_FAIL_RESPONSE),NULL);        
      }
      else
      {
        if( (conn_data = FTP_OpenDataPort((struct ip_addr *)&(ip_address.lword),ftp_port.u16)) != NULL )
        {
          //****Response Sending
          netconn_write(connfd,FTP_STOR_OK_RESPONSE,str_len(FTP_STOR_OK_RESPONSE),NULL);
         
          /*filename to write*/
          FTP_Write_File(conn_data,&alloc_rq);
         
          //Start Closing Data Stream: client closes tcp session: against protocol!!
          FTP_CloseDataPort(conn_data);
         
          //****RESPONSE: OK
          netconn_write(connfd,FTP_TRANSFER_OK_RESPONSE,str_len(FTP_TRANSFER_OK_RESPONSE),NULL);
        }
        else
        {
          return 1;/*FAIL*/
        }       
      }
    }
    /*UNKNOWN OR NOT IMPLEMENTED*/
    else
    {
      //****Response: unknown request
      netconn_write(connfd,FTP_CMD_NOT_IMP_RESPONSE,str_len(FTP_CMD_NOT_IMP_RESPONSE),NULL);
    }
   
    return 0;/*OK*/
}

/**
* Look if a file already exist with the name
*  No case sensitive
*
* @param file name to look for on FAT
* @return 0 if file was found, otherwise not
*/
uint8
FTP_Does_File_Exist(uint8 *data)
{
    UINT8 result = 1;
    UINT8 i=0;
   
    /*convert to upper case:???*/
    strupr(data);

    /*FSL: SD Mutex Enter*/
    FTP_MUTEX_ENTER
   
    if(!FAT_LS(SD_FTP_Handle,SDbuffer,(void*)data,FTP_CompareFile))
    {
      result = 0;/*file found*/
    }

    /*SD Mutex Exit*/
    FTP_MUTEX_EXIT
   
    return result;/*File not found*/
}

/**
* Callback to send files name to ethernet
*
* @param descriptor to use for sending
* @param filename string
* @return always 1
*/
UINT8
FTP_SD_send(void* var,UINT8 *fileName)
{
    struct netconn *connfd = (struct netconn *)var;
   
    /*append “\r\n”*/
    strcat( fileName, STRING_END );
    /*send files name*/
    netconn_write(connfd,fileName,strlen(fileName),NETCONN_COPY);
    return 1; 
}

/**
* Callback to check if file exists
*
* @param data to compare
* @param filename string
* @return 0 if file found, otherwise zero
*/
UINT8
FTP_CompareFile(void* var,UINT8 *fileName)
{
    UINT8 *string = (UINT8 *)var;
   
    if( !strcmp(string,(const uint8 *)SDbuffer) )
      return 0;/*File Found*/
    else
      return 1;/*File not found*/
}

/**
* Returns thru connection descriptor all files names in FAT
*
* @param connection descriptor to send files’ names
* @return 0 if read was OK, otherwise not
*/
uint8
FTP_Read_List_Of_Files(struct netconn *connfd)
{
    UINT8 u8BlockCounter=0;
    UINT8 u8BlockOffset=0;
   
    //TODO: what happens if no files at all?
   
    /*FSL: SD Mutex Enter*/
    FTP_MUTEX_ENTER

    /*dont care what it returns*/
    (void)FAT_LS(SD_FTP_Handle,SDbuffer,connfd,FTP_SD_send); 

    /*SD Mutex Exit*/
    FTP_MUTEX_EXIT
   
    return 0;/*OK*/
}

/**
* Check if filename exists in FAT system for reading
*
* @param file name to check
* @return 0 if read is possible, otherwise not
*/
uint8
FTP_Read_Is_Possible(uint8 *data)
{
  UINT8 result = 1;

  /*FSL: SD Mutex Enter*/
  FTP_MUTEX_ENTER;

  /*Look for file on SD card: uppercase is needed*/
  if( !FAT_FileOpen(SD_FTP_Handle,SDbuffer,(uint8 *)strupr(data),READ) )
  {
     result = 0;/*OK*/
  }

  /*SD Mutex Exit*/
  FTP_MUTEX_EXIT

  return result;/*Fail*/
}

/**
* Gets a file from FAT and send it to a connection descriptor
*  Call FTP_Read_Is_Possible(…)
*
* @param connection descriptor to write data read data
* @return 0 if read was OK, otherwise not
*/
uint8
FTP_Read_File(struct netconn *connfd)
{
  UINT16 u16Length;
 
  /*first call: FTP_Read_Is_Possible(…)*/

  /*FSL: SD Mutex Enter*/
  FTP_MUTEX_ENTER
    
  /*File exists so */
 
  while( (u16Length=FAT_FileRead(SD_FTP_Handle,SDbuffer)) == BLOCK_SIZE )
  {    
    /*start sending SD BLOCKs*/    
    netconn_write(connfd,SDbuffer,BLOCK_SIZE,NETCONN_COPY);
  }
  if(u16Length)
  {
    /*start sending remaining SD BLOCK*/    
    netconn_write(connfd,SDbuffer,u16Length,NETCONN_COPY);     
  }

  /*SD Mutex Exit*/
  FTP_MUTEX_EXIT

  return 0;/*OK*/ 
}

/**
* Puts a file from a connection descriptor and send it to FAT
*  First check if file do not exist to avoid duplication of files in FAT
*
* @param connection descriptor to use read data
* @param file name to write.
* @return 0 if read was OK, otherwise not
*/
uint8
FTP_Write_File(struct netconn *connfd, uint8 *data)
{
    UINT16 length;
    /*receiver buffer*/
    struct netbuf *inbuf;
    struct pbuf *q;
   
    /*Prior:string already doesnt exist on FAT*/
    /*FSL: SD Mutex Enter*/
    FTP_MUTEX_ENTER
   
    /*Write File: remaining bits: doesn’t check for file names’ duplication*/
    if( FAT_FileOpen(SD_FTP_Handle,SDbuffer,(uint8 *)strupr(data),CREATE) == FILE_CREATE_OK )
    {
       do
       {      
         /*stay here until session is: closed, received or out of memory*/
         length = netconn_rcv_req((void *)connfd, NULL, (void **)&inbuf, NETCONN_RCV_NETBUFFER);
         if( connfd->err == ERR_OK )
         {
           /*start segment index: copy all the network buffer segments*/
           q = inbuf->ptr;       
           do
           {            
             /*write as many bytes as needed*/
             FAT_FileWrite(SD_FTP_Handle,SDbuffer,q->payload,q->len);            
           }
           while( ( q = q->next ) != NULL );
          
           /*free pbuf memory*/
           netbuf_delete(inbuf);
         }
         else
         {
            /*session closed, out of memory, timeout: leave loop*/
            break;
         }      
       }while(1);
      
       /*close file*/
       FAT_FileClose(SD_FTP_Handle,SDbuffer);
    }
   
    /*SD Mutex Exit*/
    FTP_MUTEX_EXIT
   
    return length;/*Error*/ 
}

/**
* Start an embedded FTP server Task: 1 client and 1 file per transfer
*
* @param paremeter pointer to use with task
* @return none
*/
void
vBasicFTPServer( void *pvParameters )
{
    /*Connection descriptors for FTP control port*/
    struct netconn *conn, *connection;
    uint8 *alloc_rq;
   
    UINT8 i = FTP_CLOSED;/*keep session information*/

    /* Parameters are not used - suppress compiler error. */
    ( void )pvParameters;

    /*Apps buffer*/
    if( ((SDbuffer=(uint8 *)mem_malloc( BLOCK_SIZE )) == NULL) ||
        ((alloc_rq=(uint8 *)mem_malloc( FTP_REQUEST_SPACE )) == NULL) )
    {
      mem_free(SDbuffer);     
      mem_free(alloc_rq);
      /*Task no longer needed, delete it!*/
      vTaskDelete( NULL );     
    }   
    /* SD Card Initialization */
    if( (SD_FTP_Handle = FAT_INIT(SDbuffer)) == NULL )
    {
      /*delete requested memory*/
      mem_free(SDbuffer);     
      mem_free(alloc_rq);
      /*error*/
      FAT_Close();
      /*Task no longer needed, delete it!*/
      vTaskDelete( NULL );
    }
   
    /**********************FSL: socket start-up*******************************/
   
    /* Create a new TCP connection handle. */
   ** conn = netconn_new(NETCONN_TCP);**

    /* Bind the connection to port 21 on any local IP address. */
    netconn_bind(conn, NULL, FTP_TCP_CONTROL_PORT);

    /* Put the connection into LISTEN state. */
    netconn_listen(conn);

    /*set timeout for this connection*/
    netconn_set_timeout((void *)conn,0/*timeout*/);

    for(;;)/*infinite loop*/
    {
      if( i == FTP_CLOSED )/*FTP_CLOSE*/
      {
         if( (connection = netconn_accept(conn)) != NULL )
         {
            i = FTP_OPEN;
             /*set timeout for this connection*/
             netconn_set_timeout((void *)connection,0/*timeout*/);            
         }
      }
      else/*FTP_OPEN*/
      {
         /* Service connection */
         if( vFTPConnection( connection, alloc_rq ) )
         {
            i = FTP_CLOSED;
         }
      }
    }

    /*never get here!*/   
    return;
}

rtel wrote on Friday, June 08, 2012:

See my reply to your other two near identical posts.

Regards.