| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745 | 
							- /*
 
-  * lwftp.c : a lightweight FTP client using raw API of LWIP
 
-  *
 
-  * Copyright (c) 2014 GEZEDO
 
-  * All rights reserved.
 
-  *
 
-  * Redistribution and use in source and binary forms, with or without modification,
 
-  * are permitted provided that the following conditions are met:
 
-  *
 
-  * 1. Redistributions of source code must retain the above copyright notice,
 
-  *    this list of conditions and the following disclaimer.
 
-  * 2. Redistributions in binary form must reproduce the above copyright notice,
 
-  *    this list of conditions and the following disclaimer in the documentation
 
-  *    and/or other materials provided with the distribution.
 
-  * 3. The name of the author may not be used to endorse or promote products
 
-  *    derived from this software without specific prior written permission.
 
-  *
 
-  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
-  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
-  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 
-  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
-  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 
-  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
-  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
-  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 
-  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 
-  * OF SUCH DAMAGE.
 
-  *
 
-  * Author: Laurent GONZALEZ <lwip@gezedo.com>
 
-  *
 
-  */
 
- #pragma GCC diagnostic error "-Wall"
 
- #pragma GCC diagnostic error "-Wextra"
 
- #include "common_config.h"
 
- #ifdef FTP_ENABLE
 
- #include <string.h>
 
- #include <stdbool.h>
 
- #include "ftp.h"
 
- #include "lwip/tcp.h"
 
- #include "sockets.h"
 
- #include "stm32f4xx.h"
 
- #include "spi_flash.h"
 
- #include "web_params_api.h"
 
- #include "FreeRTOS.h"
 
- #include "task.h"
 
- #include "hal.h"
 
- /** Enable debugging for LWFTP */
 
- #ifndef LWFTP_DEBUG
 
- #define LWFTP_DEBUG   LWIP_DBG_ON
 
- #endif
 
- #define LWFTP_TRACE   (LWFTP_DEBUG|LWIP_DBG_TRACE)
 
- #define LWFTP_WARNING (LWFTP_DEBUG|LWIP_DBG_LEVEL_WARNING)
 
- #define LWFTP_SERIOUS (LWFTP_DEBUG|LWIP_DBG_LEVEL_SERIOUS)
 
- #define LWFTP_SEVERE  (LWFTP_DEBUG|LWIP_DBG_LEVEL_SEVERE)
 
- #define PTRNLEN(s)  s,(sizeof(s)-1)
 
- #define min(x,y) ((x)<(y)?(x):(y))
 
- lwftp_session_t ftpcfg;
 
- static unsigned received_bytes_count = 0;
 
- static char **error_ptr;
 
- /** Close control or data pcb
 
-  * @param pointer to lwftp session data
 
-  */
 
- static err_t lwftp_pcb_close(struct tcp_pcb *tpcb)
 
- {
 
-   err_t error;
 
-   tcp_err(tpcb, NULL);
 
-   tcp_recv(tpcb, NULL);
 
-   tcp_sent(tpcb, NULL);
 
-   error = tcp_close(tpcb);
 
-   if ( error != ERR_OK ) {
 
-     LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:pcb close failure, not implemented\n"));
 
-   }
 
-   return ERR_OK;
 
- }
 
- /** Send data
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param number of bytes sent
 
-  */
 
- static err_t lwftp_send_next_data(lwftp_session_t *s)
 
- {
 
-   const char *data;
 
-   int len = 0;
 
-   err_t error = ERR_OK;
 
-   if (s->data_source) {
 
-     len = s->data_source(s->data_handle, &data, s->data_pcb->mss);
 
-     if (len) {
 
-       LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:sending %d bytes of data\n",len));
 
-       error = tcp_write(s->data_pcb, data, len, 0);
 
-       if (error!=ERR_OK) {
 
-         LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:write failure (%s), not implemented\n",lwip_strerr(error)));
 
-       }
 
-     }
 
-   }
 
-   if (!len) {
 
-     LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:end of file\n"));
 
-     lwftp_pcb_close(s->data_pcb);
 
-     s->data_pcb = NULL;
 
-   }
 
-   return ERR_OK;
 
- }
 
- /** Handle data connection incoming data
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param pointer to incoming pbuf
 
-  * @param state of incoming process
 
-  */
 
- static err_t lwftp_data_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
 
- {
 
-   (void)err;
 
-   lwftp_session_t *s = (lwftp_session_t*)arg;
 
-   if (p) {
 
-     if (s->data_sink) {
 
-       struct pbuf *q;
 
-       for (q=p; q; q=q->next) {
 
-         s->data_sink(s->data_handle, q->payload, q->len);
 
-       }
 
-     } else {
 
-       LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp: sinking %d bytes\n",p->tot_len));
 
-     }
 
-     tcp_recved(tpcb, p->tot_len);
 
-     pbuf_free(p);
 
-   } else {
 
-     if (s->data_sink) {
 
-       s->data_sink(s->data_handle, NULL, 0);
 
-     }
 
-     // NULL pbuf shall lead to close the pcb.
 
-     if (s->data_pcb) {
 
-       lwftp_pcb_close(s->data_pcb);
 
-       s->data_pcb = NULL;
 
-     }
 
-   }
 
-   return ERR_OK;
 
- }
 
- /** Handle data connection acknowledge of sent data
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param number of bytes sent
 
-  */
 
- static err_t lwftp_data_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
 
- {
 
-   (void)tpcb;
 
-   lwftp_session_t *s = (lwftp_session_t*)arg;
 
-   if ( s->data_source ) {
 
-     s->data_source(s->data_handle, NULL, len);
 
-   }
 
-   return lwftp_send_next_data(s);
 
- }
 
- /** Handle data connection error
 
-  * @param pointer to lwftp session data
 
-  * @param state of connection
 
-  */
 
- static void lwftp_data_err(void *arg, err_t err)
 
- {
 
-   LWIP_UNUSED_ARG(err);
 
-   if (arg != NULL) {
 
-     lwftp_session_t *s = (lwftp_session_t*)arg;
 
-     LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:failed/error connecting for data to server (%s)\n",lwip_strerr(err)));
 
-     s->control_state = LWFTP_QUIT;  // gracefully exit on data error
 
-     s->data_pcb = NULL; // No need to de-allocate PCB
 
-   }
 
- }
 
- /** Process newly connected PCB
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param state of connection
 
-  */
 
- static err_t lwftp_data_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
 
- {
 
-   (void)tpcb;
 
-   lwftp_session_t *s = (lwftp_session_t*)arg;
 
-   if ( err == ERR_OK ) {
 
-     LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected for data to server\n"));
 
-     s->data_state = LWFTP_CONNECTED;
 
-   } else {
 
-     LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in data_connected (%s)\n",lwip_strerr(err)));
 
-   }
 
-   return err;
 
- }
 
- /** Open data connection for passive transfer
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to incoming PASV response
 
-  */
 
- static err_t lwftp_data_open(lwftp_session_t *s, struct pbuf *p)
 
- {
 
-   err_t error;
 
-   char *ptr;
 
-   ip_addr_t data_server;
 
-   u16_t data_port;
 
-   // Find server connection parameter
 
-   ptr = strchr(p->payload, '(');
 
-   if (!ptr) return ERR_BUF;
 
-   do {
 
-     unsigned int a = strtoul(ptr+1,&ptr,10);
 
-     unsigned int b = strtoul(ptr+1,&ptr,10);
 
-     unsigned int c = strtoul(ptr+1,&ptr,10);
 
-     unsigned int d = strtoul(ptr+1,&ptr,10);
 
-     IP4_ADDR(&data_server,a,b,c,d);
 
-   } while(0);
 
-   data_port  = strtoul(ptr+1,&ptr,10) << 8;
 
-   data_port |= strtoul(ptr+1,&ptr,10) & 255;
 
-   if (*ptr!=')') return ERR_BUF;
 
-   // Open data session
 
-   tcp_arg(s->data_pcb, s);
 
-   tcp_err(s->data_pcb, lwftp_data_err);
 
-   tcp_recv(s->data_pcb, lwftp_data_recv);
 
-   tcp_sent(s->data_pcb, lwftp_data_sent);
 
-   error = tcp_connect(s->data_pcb, &data_server, data_port, lwftp_data_connected);
 
-   return error;
 
- }
 
- /** Send a message to control connection
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to message string
 
-  */
 
- static err_t lwftp_send_msg(lwftp_session_t *s, const char* msg, size_t len)
 
- {
 
-   err_t error;
 
-   LWIP_DEBUGF(LWFTP_TRACE,("lwftp:sending %s",msg));
 
-   error = tcp_write(s->control_pcb, msg, len, 0);
 
-   if ( error != ERR_OK ) {
 
-       LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:cannot write (%s)\n",lwip_strerr(error)));
 
-   }
 
-   return error;
 
- }
 
- /** Close control connection
 
-  * @param pointer to lwftp session data
 
-  * @param result to pass to callback fn (if called)
 
-  */
 
- static void lwftp_control_close(lwftp_session_t *s, int result)
 
- {
 
-   if (s->control_pcb) {
 
-     lwftp_pcb_close(s->control_pcb);
 
-     s->control_pcb = NULL;
 
-   }
 
-   s->control_state = LWFTP_CLOSED;
 
-   if ( (result >= 0) && s->done_fn ) {
 
-     s->done_fn(s->data_handle, result);
 
-   }
 
- }
 
- static void set_timeout(struct tcp_pcb *tpcb, unsigned seconds)
 
- {
 
-   struct timeval timeout;
 
-   timeout.tv_sec = seconds;
 
-   timeout.tv_usec = 0;
 
-   setsockopt(tpcb, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
 
- }
 
- /** Main client state machine
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param pointer to incoming data
 
-  */
 
- static void lwftp_control_process(lwftp_session_t *s, struct tcp_pcb *tpcb, struct pbuf *p)
 
- {
 
-   (void)tpcb;
 
-   unsigned response = 0;
 
-   int result = LWFTP_RESULT_ERR_SRVR_RESP;
 
-   // Try to get response number
 
-   if (p) {
 
-     response = strtoul(p->payload, NULL, 10);
 
-     LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:got response %d\n",response));
 
-   }
 
-   switch (s->control_state) {
 
-     case LWFTP_CONNECTED:
 
-       if (response>0) {
 
-         if (response==220) {
 
-           lwftp_send_msg(s, PTRNLEN("USER "));
 
-           lwftp_send_msg(s, s->settings->user, strlen(s->settings->user));
 
-           lwftp_send_msg(s, PTRNLEN("\n"));
 
-           s->control_state = LWFTP_USER_SENT;
 
-         } else {
 
-           s->error = "The server doesn't like us";
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       } else {
 
-         s->error = "The server doesn't greet us";
 
-         s->control_state = LWFTP_QUIT;
 
-       }
 
-       break;
 
-     case LWFTP_USER_SENT:
 
-       if (response>0) {
 
-         if (response==331) {
 
-           lwftp_send_msg(s, PTRNLEN("PASS "));
 
-           lwftp_send_msg(s, s->settings->pass, strlen(s->settings->pass));
 
-           lwftp_send_msg(s, PTRNLEN("\n"));
 
-           s->control_state = LWFTP_PASS_SENT;
 
-         } else if (response==230) {
 
-           goto anonymous;
 
-         } else {
 
-           s->error = "Wrong user name";
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_PASS_SENT:
 
-       if (response>0) {
 
-         if (response==230) {
 
- anonymous:
 
-           lwftp_send_msg(s, PTRNLEN("TYPE I\n"));
 
-           s->control_state = LWFTP_TYPE_SENT;
 
-         } else {
 
-           s->error = "Wrong password";
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_TYPE_SENT:
 
-       if (response>0) {
 
-         if (response==200) {
 
-           lwftp_send_msg(s, PTRNLEN("PASV\n"));
 
-           s->control_state = LWFTP_PASV_SENT;
 
-         } else {
 
-           s->error = "The server doesn't support binary files";
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_PASV_SENT:
 
-       if (response>0) {
 
-         if (response==227) {
 
-           lwftp_data_open(s,p);
 
-           switch (s->target_state) {
 
-             case LWFTP_STOR_SENT:
 
-               lwftp_send_msg(s, PTRNLEN("STOR "));
 
-               break;
 
-             case LWFTP_RETR_SENT:
 
-               lwftp_send_msg(s, PTRNLEN("RETR "));
 
-               break;
 
-             default:
 
-               //LOG_ERROR("Unexpected internal state");
 
-               s->target_state = LWFTP_QUIT;
 
-             }
 
-           lwftp_send_msg(s, s->settings->remote_path, strlen(s->settings->remote_path));
 
-           lwftp_send_msg(s, PTRNLEN("\n"));
 
-           s->control_state = s->target_state;
 
-         } else {
 
-           s->error = "The server doesn't support PASV";
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_RETR_SENT:
 
-       if (response>0) {
 
-         if (response==150) {
 
-           s->control_state = LWFTP_XFERING;
 
-           set_timeout(s->control_pcb, 0);
 
-         } else if (response==550) {
 
-             s->control_state = LWFTP_QUIT;
 
-             s->error = "Failed to open file";
 
-             LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s '%s'\n", error, s->settings->remote_path));
 
-         }
 
-         else {
 
-           s->error = "The server doesn't start sending the file";
 
-           s->control_state = LWFTP_QUIT;
 
-           LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 150, received %d\n",response));
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_STOR_SENT:
 
-       if (response>0) {
 
-         if (response==150) {
 
-           s->control_state = LWFTP_XFERING;
 
-           lwftp_data_sent(s,NULL,0);
 
-         } else {
 
-           s->control_state = LWFTP_QUIT;
 
-         }
 
-       }
 
-       break;
 
-     case LWFTP_XFERING:
 
-       if (response>0) {
 
-         if (response==226) {
 
-           s->data_state = LWFTP_XFERING;  // signal transfer OK
 
-         } else {
 
-           LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 226, received %d\n",response));
 
-         }
 
-         // Quit anyway after any message received during STOR
 
-         s->control_state = LWFTP_QUIT;
 
-       }
 
-       break;
 
-     case LWFTP_QUIT_SENT:
 
-       if (response>0) {
 
-         if (response==221) {
 
-           if (s->data_state == LWFTP_XFERING){ // check for transfer OK
 
-             result = LWFTP_RESULT_OK;
 
-           }
 
-         } else {
 
-           LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 221, received %d\n",response));
 
-         }
 
-         s->control_state = LWFTP_CLOSING;
 
-       }
 
-       break;
 
-     default:
 
-       LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:unhandled state (%d)\n",s->control_state));
 
-   }
 
-   // Free receiving pbuf if any
 
-   if (p) {
 
-     pbuf_free(p);
 
-   }
 
-   // Handle second step in state machine
 
-   switch ( s->control_state ) {
 
-     case LWFTP_QUIT:
 
-       lwftp_send_msg(s, PTRNLEN("QUIT\n"));
 
-       s->control_state = LWFTP_QUIT_SENT;
 
-       break;
 
-     case LWFTP_CLOSING:
 
-       // this function frees s, no use of s is allowed after
 
-       return lwftp_control_close(s, result);
 
-     default:;
 
-   }
 
- }
 
- /** Handle control connection incoming data
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param pointer to incoming pbuf
 
-  * @param state of incoming process
 
-  */
 
- static err_t lwftp_control_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
 
- {
 
-   lwftp_session_t *s = (lwftp_session_t*)arg;
 
-   if ( err == ERR_OK ) {
 
-     if (p) {
 
-       tcp_recved(tpcb, p->tot_len);
 
-       lwftp_control_process(s, tpcb, p);
 
-     } else {
 
-       LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
 
-       lwftp_control_close(s, LWFTP_RESULT_ERR_CLOSED);
 
-     }
 
-   } else {
 
-     LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:failed to receive (%s)\n",lwip_strerr(err)));
 
-     lwftp_control_close(s, LWFTP_RESULT_ERR_UNKNOWN);
 
-   }
 
-   return err;
 
- }
 
- /** Handle control connection acknowledge of sent data
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param number of bytes sent
 
-  */
 
- static err_t lwftp_control_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
 
- {
 
-   (void)arg;
 
-   (void)tpcb;
 
-   (void)len;
 
-   LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:successfully sent %d bytes\n",len));
 
-   return ERR_OK;
 
- }
 
- /** Handle control connection error
 
-  * @param pointer to lwftp session data
 
-  * @param state of connection
 
-  */
 
- static void lwftp_control_err(void *arg, err_t err)
 
- {
 
-   LWIP_UNUSED_ARG(err);
 
-   if (arg != NULL) {
 
-     lwftp_session_t *s = (lwftp_session_t*)arg;
 
-     int result;
 
-     if( s->control_state == LWFTP_CLOSED ) {
 
-       s->error = "failed to connect to server";
 
-       LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s (%s)\n",lwip_strerr(err)));
 
-       result = LWFTP_RESULT_ERR_CONNECT;
 
-     } else {
 
-       s->error = "connection closed by remote host";
 
-       LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
 
-       result = LWFTP_RESULT_ERR_CLOSED;
 
-     }
 
-     s->control_pcb = NULL; // No need to de-allocate PCB
 
-     lwftp_control_close(s, result);
 
-   }
 
- }
 
- /** Process newly connected PCB
 
-  * @param pointer to lwftp session data
 
-  * @param pointer to PCB
 
-  * @param state of connection
 
-  */
 
- static err_t lwftp_control_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
 
- {
 
-   (void)tpcb;
 
-   lwftp_session_t *s = (lwftp_session_t*)arg;
 
-   if ( err == ERR_OK ) {
 
-     LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected to server\n"));
 
-       s->control_state = LWFTP_CONNECTED;
 
-   } else {
 
-     LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in control_connected (%s)\n",lwip_strerr(err)));
 
-   }
 
-   return err;
 
- }
 
- /** Store data to a remote file
 
-  * @param Session structure
 
-  */
 
- err_t lwftp_store(lwftp_session_t *s)
 
- {
 
-   err_t error;
 
-   // Check user supplied data
 
-   if ( (s->control_state!=LWFTP_CLOSED) ||
 
-        !s->settings->remote_path ||
 
-        s->control_pcb ||
 
-        s->data_pcb ||
 
-        !s->settings->user ||
 
-        !s->settings->pass )
 
-   {
 
-     LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid session data\n"));
 
-     return ERR_ARG;
 
-   }
 
-   // Get sessions pcb
 
-   s->control_pcb = tcp_new();
 
-   if (!s->control_pcb) {
 
-     LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc control_pcb (low memory?)\n"));
 
-     error = ERR_MEM;
 
-     goto exit;
 
-   }
 
-   s->data_pcb = tcp_new();
 
-   if (!s->data_pcb) {
 
-     LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc data_pcb (low memory?)\n"));
 
-     error = ERR_MEM;
 
-     goto close_pcb;
 
-   }
 
-   set_timeout(s->control_pcb, 5);
 
-   set_timeout(s->data_pcb, 5);
 
-   // Open control session
 
-   tcp_arg(s->control_pcb, s);
 
-   tcp_err(s->control_pcb, lwftp_control_err);
 
-   tcp_recv(s->control_pcb, lwftp_control_recv);
 
-   tcp_sent(s->control_pcb, lwftp_control_sent);
 
-   error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
 
-   if ( error == ERR_OK ) goto exit;
 
-   LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
 
- close_pcb:
 
-   // Release pcbs in case of failure
 
-   lwftp_control_close(s, -1);
 
- exit:
 
-   return error;
 
- }
 
- err_t lwftp_retr(lwftp_session_t *s)
 
- {
 
-   s->target_state = LWFTP_RETR_SENT;
 
-   err_t error;
 
-   // Check user supplied data
 
-   if (!s->settings->remote_path) {
 
-     s->error = "empty remote path";
 
-     return ERR_ARG;
 
-   }
 
-   if (!s->settings->user) {
 
-     s->error = "empty user name";
 
-     return ERR_ARG;
 
-   }
 
-   if (!s->settings->pass) {
 
-     s->error = "empty password";
 
-     return ERR_ARG;
 
-   }
 
-   if (s->control_state != LWFTP_CLOSED || s->control_pcb) {
 
-     // previous connection is incomplete
 
-     lwftp_control_close(s, -1);
 
-   }
 
-   if (s->data_pcb) {
 
-     lwftp_pcb_close(s->data_pcb);
 
-   }
 
-   // Get sessions pcb
 
-   s->control_pcb = tcp_new();
 
-   if (!s->control_pcb) {
 
-     s->error = "cannot alloc control_pcb (low memory?)";
 
-     error = ERR_MEM;
 
-     goto exit;
 
-   }
 
-   s->data_pcb = tcp_new();
 
-   if (!s->data_pcb) {
 
-     s->error = "cannot alloc data_pcb (low memory?)";
 
-     error = ERR_MEM;
 
-     goto close_pcb;
 
-   }
 
-   // Open control session
 
-   tcp_arg(s->control_pcb, s);
 
-   tcp_err(s->control_pcb, lwftp_control_err);
 
-   tcp_recv(s->control_pcb, lwftp_control_recv);
 
-   tcp_sent(s->control_pcb, lwftp_control_sent);
 
-   error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
 
-   if ( error == ERR_OK ) goto exit;
 
-   LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
 
-   s->error = "cannot connet control_pcb";
 
- close_pcb:
 
-   // Release pcbs in case of failure
 
-   lwftp_control_close(s, -1);
 
- exit:
 
-   return error;
 
- }
 
- //static void ftp_retr_callback(void *arg, int result)
 
- //{
 
- //  lwftp_session_t *s = (lwftp_session_t *)arg;
 
- //
 
- //  if (result != LWFTP_RESULT_OK) {
 
- //      //LOG_ERROR("retr failed (%d)", result);
 
- //      return lwftp_close(s);
 
- //  }
 
- //  lwftp_close(s);
 
- //}
 
- static bool validate_spif_firmware(uint32_t fw_len)
 
- {
 
-   const uint32_t spif_firmware_offset = SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET;
 
-   // check the firmware revision id
 
-   char rev[HW_REV_LEN];
 
-   spi_flash_read(spif_firmware_offset + HW_REV_OFFSET, &rev, sizeof(rev), 0);
 
-   if (strncmp(rev, HW_REV, sizeof(rev))) {
 
-     printf("HW revision mismatch: expected %s, found %s\r\n", HW_REV, rev);
 
-     return false;
 
-   }
 
-   // check if the firmware length is correct
 
-   if (fw_len != MAIN_FW_SIZE) {
 
-     printf("ftp: firmware size mismatch: expected %d, got %ld\r\n", MAIN_FW_SIZE, fw_len);
 
-     return false;
 
-   }
 
-   uint32_t expected_crc;
 
-   const uint32_t crc_offset = USER_FLASH_CRC_ADDRESS - USER_FLASH_FIRST_PAGE_ADDRESS;
 
-   spi_flash_read(spif_firmware_offset + crc_offset, &expected_crc, sizeof(expected_crc), 0);
 
-   // calculate CRC
 
-   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
 
-   CRC->CR = 1;
 
-   for (uint32_t offset = 0; offset < crc_offset; offset += 4) {
 
-     uint32_t data;
 
-     spi_flash_read(spif_firmware_offset + offset, &data, sizeof(data), 0);
 
-     CRC->DR = data;
 
-   }
 
-   uint32_t calculated_crc = CRC->DR;
 
-   if (expected_crc != calculated_crc) {
 
-     printf("ftp: calculated CRC (%lx) doesn't match the expected CRC (%lx)!\r\n", calculated_crc, expected_crc);
 
-     return false;
 
-   }
 
-   return true;
 
- }
 
- static void erase_spif_firmware()
 
- {
 
-   printf("ftp: erasing SPI firmware partition...\r\n");
 
-   for (int sec = 0; sec < FIRMWARE_UPDATE_SECTOR_COUNT; ++sec) {
 
-     spi_flash_erase_sector(SPI_FLASH_SECTOR_SIZE * (FIRMWARE_UPDATE_SECTOR_OFFSET + sec), 0);
 
-   }
 
- }
 
- static unsigned data_sink(void *arg, const char* ptr, unsigned len)
 
- {
 
-   (void)arg;
 
-   if (ptr && len) {
 
-     // we received some data from the FTP server
 
-     if (received_bytes_count == 0) {
 
-       // we need to erase the flash before we can write it
 
-       erase_spif_firmware();
 
-     }
 
-     if (received_bytes_count + len > MAIN_FW_SIZE) {
 
-       printf("ftp: the firmware is too big! aborting the download\r\n");
 
-       return 0;
 
-     }
 
-     spi_flash_write(SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET + received_bytes_count, ptr, len, 0);
 
-     received_bytes_count += len;
 
-   } else {
 
-     printf("ftp: the firmware is downloaded, verifying...\r\n");
 
-     uint32_t fw_size = received_bytes_count;
 
-     bool good_firmware = validate_spif_firmware(fw_size);
 
-     if (good_firmware) {
 
-       printf("ftp: the firmware is valid, rebooting...\r\n");
 
-       set_act_source(FTP_ACT);
 
-       HTTP_StartResetTask(true);
 
-     } else {
 
-       // erase it so the bootloader won't try to verify it every time
 
-       erase_spif_firmware();
 
-     }
 
-   }
 
-   return len;
 
- }
 
- void start_ftp_client(lwftp_session_t *s)
 
- {
 
-   received_bytes_count = 0;
 
-   s->error = NULL;
 
-   error_ptr = &s->error;
 
-   s->data_sink = data_sink;
 
-   //s->done_fn = ftp_retr_callback;
 
-   lwftp_retr(s);
 
-   // FTP session will continue with the connection callback
 
- }
 
- char *get_ftp_progress()
 
- {
 
-   if (*error_ptr) {
 
-     return *error_ptr;
 
-   } else {
 
-     unsigned progress = received_bytes_count * 100 / MAIN_FW_SIZE;
 
-     static char progress_str_buf[4];
 
-     snprintf(progress_str_buf, sizeof(progress_str_buf), "%u", progress);
 
-     return progress_str_buf;
 
-   }
 
- }
 
- #endif // FTP_ENABLE
 
 
  |