From 31eb8eb589ff8428a2e84e4b2f33e8d3d5affed3 Mon Sep 17 00:00:00 2001 From: anschrammh Date: Sat, 12 Oct 2019 23:20:25 +0200 Subject: [PATCH] Implementing FTP server --- src/software_test/tcpServer_test/Dictionary.h | 4 +- .../tcpServer_test/FTPClient.cpp | 57 +++++++ src/software_test/tcpServer_test/FTPClient.h | 21 ++- src/software_test/tcpServer_test/FTPServer.h | 148 +++++++++++++++++- .../tcpServer_test/StringEntity.cpp | 33 ++++ src/software_test/tcpServer_test/WEBServer.h | 4 +- .../tcpServer_test/definition.cpp | 51 ++++++ src/software_test/tcpServer_test/definition.h | 60 +++++++ .../tcpServer_test/tcpServer_test.ino | 2 + 9 files changed, 370 insertions(+), 10 deletions(-) create mode 100644 src/software_test/tcpServer_test/StringEntity.cpp create mode 100644 src/software_test/tcpServer_test/definition.cpp create mode 100644 src/software_test/tcpServer_test/definition.h diff --git a/src/software_test/tcpServer_test/Dictionary.h b/src/software_test/tcpServer_test/Dictionary.h index b9399f5..42b69d7 100644 --- a/src/software_test/tcpServer_test/Dictionary.h +++ b/src/software_test/tcpServer_test/Dictionary.h @@ -19,8 +19,8 @@ namespace DictionaryHelper { if(string == NULL) { - _string = (char *) malloc((sizeof(char)) * 2); //+1 for the string terminating character - strcpy(_string, ""); + _string = (char *) malloc((sizeof(char))); + _string[0] = '\0'; } else { diff --git a/src/software_test/tcpServer_test/FTPClient.cpp b/src/software_test/tcpServer_test/FTPClient.cpp index 4c3b04d..8cd4175 100644 --- a/src/software_test/tcpServer_test/FTPClient.cpp +++ b/src/software_test/tcpServer_test/FTPClient.cpp @@ -1 +1,58 @@ #include "FTPClient.h" + +FTPClient::FTPClient(WiFiClient client, uint8_t id, uint16_t clientCommandDataBufferSize) : TCPClient(client, id, clientCommandDataBufferSize), +_ftpCommand({'\0'}), +_cmdParameters(NULL), +_loggedIn(false), +_username(NULL), +_ftpClientState(FTPServer::FTPClientState::WAITING_FOR_COMMANDS), +_binaryFlag(FTPServer::BinaryFlag::OFF) +{ + +} + +FTPClient::~FTPClient() +{ + delete _cmdParameters; + free(_username); +} + +void FTPClient::setDataClient(WiFiClient dataClient) +{ + _dataClient = _dataClient; +} + +boolean FTPClient::parseCommandAndParameters() +{ + //We remove the cr lf at the end + char *cr = strchr((char *)_data,'\r'); *cr = '\0'; + char *cmdDelimiter = strchr((char *)_data,' '); + + if(cmdDelimiter == NULL) //It means that we do not have any parameters + { + cmdDelimiter = (char *)_data + strlen((char *)_data) - 1; + strcpy(_ftpCommand, (char *)_data); + } + else //we do + { + strncpy(_ftpCommand, (char *)_data, cmdDelimiter - (char *)_data); + _ftpCommand[cmdDelimiter - (char *)_data] = '\0'; // /!\ strncpy does not append the terminating string character + } + + //We get the parameters : + DictionaryHelper::StringEntity params(cmdDelimiter+1); //+1 to skip the first space + delete _cmdParameters; + _cmdParameters = params.split(' '); + + //At the end, we flush the buffer: + freeDataBuffer(_dataSize); +} + +void FTPClient::setUsername(const char *username) +{ + if(username != NULL) + { + _username = (char *) malloc((sizeof(char) * strlen(username)) + 1); + strcpy(_username, username); + } +} diff --git a/src/software_test/tcpServer_test/FTPClient.h b/src/software_test/tcpServer_test/FTPClient.h index 9adda9e..8be23e7 100644 --- a/src/software_test/tcpServer_test/FTPClient.h +++ b/src/software_test/tcpServer_test/FTPClient.h @@ -2,12 +2,31 @@ #define FTPCLIENT_H #include "TCPClient.h" +#include "FTPServer.h" +#include "Dictionary.h" -class FTPClient +class FTPClient : public TCPClient { + template + friend class FTPServer; public: + FTPClient(WiFiClient client, uint8_t id, uint16_t clientCommandDataBufferSize = 255); + virtual ~FTPClient(); protected: private: + FTPClient(const FTPClient &Object) : TCPClient(Object){} + void setDataClient(WiFiClient dataClient); //Also known as the data socket + boolean parseCommandAndParameters(void); + void setUsername(const char *username); + + char _ftpCommand[5]; + Dictionary *_cmdParameters; + boolean _loggedIn; + char *_username; + + FTPServer::FTPClientState _ftpClientState; + FTPServer::BinaryFlag _binaryFlag; + WiFiClient _dataClient; //data socket }; #endif //FTPCLIENT_H diff --git a/src/software_test/tcpServer_test/FTPServer.h b/src/software_test/tcpServer_test/FTPServer.h index cd35e91..ff9c8ae 100644 --- a/src/software_test/tcpServer_test/FTPServer.h +++ b/src/software_test/tcpServer_test/FTPServer.h @@ -2,20 +2,31 @@ #define FTPSERVER_H #include "TCPServer.h" +#define DEBUG_FTPS template class FTPServer : public TCPServer { public: - FTPServer(unsigned int port = 22, const char login = "", const char password = "", uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer(port, maxClient, clientCommandDataBufferSize), _login(NULL), _password(NULL) + enum FTPClientState {WAITING_FOR_COMMANDS}; + enum BinaryFlag {OFF = 0, ON}; + + FTPServer(unsigned int port = 21, const char *login = NULL, const char *password = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer(port, maxClient, clientCommandDataBufferSize), + _login(NULL), + _password(NULL), + _dataServer(1024) { - _login = (char *)malloc((sizeof(char) * strlen(login)) + 1); - if(_login != NULL) + if(login != NULL) + { + _login = (char *)malloc((sizeof(char) * strlen(login)) + 1); strcpy(_login, login); + } - _password = (char *)malloc((sizeof(char) * strlen(password)) + 1); - if(_password != NULL) + if(password != NULL) + { + _password = (char *)malloc((sizeof(char) * strlen(password)) + 1); strcpy(_password, password); + } } virtual ~FTPServer() @@ -24,9 +35,136 @@ class FTPServer : public TCPServer } protected: + virtual T* createNewClient(WiFiClient wc) + { + return new T(wc, TCPServer::freeClientId(), TCPServer::_clientDataBufferSize); + } + + virtual void greetClient(T *client) + { + //The first time the client connects, we send the server's information + client->_client.println("220 Welcome to the ESP8266SwissArmyBoard embedded FTP server."); + client->_clientState = TCPClient::HANDLED; + } + + virtual void processClientData(T *client) + { + + #ifdef DEBUG_FTPS + if(client->_newDataAvailable) + { + Serial.print("Client --> ");Serial.print(client->_id);Serial.print(" : ");Serial.print((char *)client->_data);Serial.println("#"); + } + #endif + + switch(client->_ftpClientState) + { + case WAITING_FOR_COMMANDS: + processCommands(client); + break; + } + } + private: + void processCommands(T *client) + { + if(!client->parseCommandAndParameters()) //Failed to retrieve command and parameters + { + //We can close the connection or do other things + return; + } + + #ifdef DEBUG_FTPS + Serial.printf("Issued command : '%s'\n",client->_ftpCommand); + Serial.println("Get params :"); + for(int i = 0; i < client->_cmdParameters->count(); i++) + { + Serial.print(client->_cmdParameters->getParameter(i));Serial.print(" : ");Serial.printf("'%s'\n",client->_cmdParameters->getAt(i)->getString()); + } + #endif + + if(strcmp(client->_ftpCommand,"USER") == 0) + { + //We check if we set a login and a password : + if(_login != NULL && _password != NULL) + { + if(client->_cmdParameters->count() > 0) + { + client->_client.println("331 User name okay, need password."); + client->setUsername(client->_cmdParameters->getAt(0)->getString()); + } + else + client->_client.println("530 Username required."); + } + else //The ftp access is open + { + client->_client.println("230 User logged in, proceed."); + } + } + else if(strcmp(client->_ftpCommand,"PASS") == 0) + { + //We now check if the username and password correspond + if(client->_cmdParameters->count() > 0) + { + if(strcmp(_login,client->_username) == 0 && strcmp(_password, client->_cmdParameters->getAt(0)->getString()) == 0) + { + client->_loggedIn = true; + client->_client.println("230 User logged in, proceed."); + } + else + { + client->_client.println("530 Wrong username or password !."); + } + } + else + { + client->_client.println("530 Password required."); + } + } + else if(strcmp(client->_ftpCommand,"PWD") == 0) + { + client->_client.println("257 \"/FTP\""); + } + else if(strcmp(client->_ftpCommand,"TYPE") == 0) + { + if(client->_cmdParameters->count() > 0) + { + switch(client->_cmdParameters->getAt(0)->getString()[0]) + { + case 'I': + client->_binaryFlag = ON; + client->_client.println("200 Command okay."); + break; + case 'L': + client->_binaryFlag = ON; + client->_client.println("200 Command okay."); + break; + case 'A': + client->_binaryFlag = OFF; + client->_client.println("200 Command okay."); + break; + default: + client->_client.println("504 Command not implemented for TYPE."); + } + } + else + { + client->_client.println("504 Command not implemented for TYPE."); + } + } + else if(strcmp(client->_ftpCommand,"PASV") == 0) + { + _dataServer.begin(); + client->_client.printf("227 Entering Passive Mode (%d,%d,%d,%d,%d,%d).\r\n", 192,168,0,29,1024/256, 1024%256); + } + else + client->_client.println("502 Command not implemented."); + } + char *_login; char *_password; + + WiFiServer _dataServer; //In passive mode, the FTP server opens two different ports (one for the commands and the other for the data stream) }; #endif //FTPSERVER_H diff --git a/src/software_test/tcpServer_test/StringEntity.cpp b/src/software_test/tcpServer_test/StringEntity.cpp new file mode 100644 index 0000000..6321bb7 --- /dev/null +++ b/src/software_test/tcpServer_test/StringEntity.cpp @@ -0,0 +1,33 @@ +#include "Dictionary.h" +#include "definition.h" + +Dictionary *DictionaryHelper::StringEntity::split(char character) +{ + Dictionary *ref = NULL; + unsigned int i(0), counter(0); + char *parseBuffer(NULL); + + if(_string == NULL)return NULL; + + ref = new Dictionary(); + + while(_string[i] != '\0') + { + if(_string[i] == character) + { + ref->add(counter++, parseBuffer); + free(parseBuffer);parseBuffer = NULL; + } + else + { + parseBuffer = addChar(parseBuffer, _string[i]); + } + + i++; + } + + ref->add(counter++,parseBuffer); + free(parseBuffer);parseBuffer = NULL; + + return ref; +} diff --git a/src/software_test/tcpServer_test/WEBServer.h b/src/software_test/tcpServer_test/WEBServer.h index 536d984..9e01b3e 100644 --- a/src/software_test/tcpServer_test/WEBServer.h +++ b/src/software_test/tcpServer_test/WEBServer.h @@ -36,7 +36,7 @@ class WEBServer : public TCPServer uint16_t maxBodyBuffer; }; - WEBServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 512) : TCPServer(port, maxClient, clientDataBufferSize) {} + WEBServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 255) : TCPServer(port, maxClient, clientDataBufferSize) {} boolean addApiRoutine(const char *uri, boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*), void *pData, HttpRequestMethod HRM = UNDEFINED) { @@ -53,7 +53,7 @@ class WEBServer : public TCPServer private: virtual T* createNewClient(WiFiClient wc) { - return new T(wc, TCPServer::freeClientId()); + return new T(wc, TCPServer::freeClientId(), TCPServer::_clientDataBufferSize); } virtual void greetClient(T *client) diff --git a/src/software_test/tcpServer_test/definition.cpp b/src/software_test/tcpServer_test/definition.cpp new file mode 100644 index 0000000..c4aed96 --- /dev/null +++ b/src/software_test/tcpServer_test/definition.cpp @@ -0,0 +1,51 @@ +#include "definition.h" + +char *addChar(char *pointer, const char character) +{ + char *tempAddr = NULL; + if(pointer == NULL) + { + tempAddr = (char *) realloc(pointer, 2*sizeof(char)); + if(tempAddr == NULL) + return NULL; + else + { + pointer = tempAddr; + pointer[0] = character; + pointer[1] = '\0'; + } + } + else + { + tempAddr = (char *) realloc(pointer, (strlen(pointer)+2)*sizeof(char)); + if(tempAddr == NULL) + { + free(pointer); + return NULL; + } + else + { + pointer = tempAddr; + pointer[strlen(pointer)+1] = '\0'; + pointer[strlen(pointer)] = character; + } + } + + return pointer; +} + +char *dateTimeFormater(char *pointer, const uint8_t value, const char character) +{ + if(pointer == NULL) + return pointer; + + if(value < 10) + { + sprintf(pointer,"%d", value); + *(pointer+1) = *(pointer);*(pointer) = character;*(pointer+2) = '\0'; + } + else + sprintf(pointer,"%d", value); + + return pointer; +} diff --git a/src/software_test/tcpServer_test/definition.h b/src/software_test/tcpServer_test/definition.h new file mode 100644 index 0000000..85b90b3 --- /dev/null +++ b/src/software_test/tcpServer_test/definition.h @@ -0,0 +1,60 @@ +#ifndef DEFINITION_H +#define DEFINITION_H + +#include +#include + +typedef enum { GPIO_0 = 0, + GPIO_1_TX = 1, + GPIO_2 = 2, + GPIO_3_RX = 3, + GPIO_4_SDA = 4, + GPIO_5_SCL = 5, + GPIO_10 = 10, + GPIO_12_MISO = 12, + GPIO_13_MOSI = 13, + GPIO_14_CLK = 14, + GPIO_15 = 15, + GPIO_16 = 16, + ADC = A0, + DEFAULT_PIN = -1 } Pin; + +#define AP_AND_STA_ENABLED_ERR B00000001 +#define AP_SETUP_ERR B00000010 +#define STA_SETUP_ERR B00000100 + +#define NO_ERROR 0 + +#define NO_CURRENT_VIEW NULL +#define LAST_VIEW -1 +#define RESERVED_VIEW_UID -2 + +#define BATT_FULL 870 //8.4v +#define BATT_EMPTY 775 //7.4v +#define BATT_DIFF 95 +#define USB_THRESHOLD 600 + +//SD card file structure : +#define AP_CFG_FILE "/CONFIG/AP.CFG" +#define STA_CFG_FILE "/CONFIG/STA.CFG" +#define WWW_DIR "/WWW" +#define LOG_DIR "/LOGS" +#define FTP_DIR "/FTP" + +typedef enum { OR_0 = 2, OR_90 = 3, OR_180 = 0, OR_270 = 1 } Orientation; + +typedef enum { BIT = 0, BYTE, KBIT, KBYTE, MBIT, MBYTE, GBIT, GBYTE } SizeUnit; + +//Data structure for the view handling +typedef struct viewLink{ + boolean (*viewLogicFunction)(Adafruit_SSD1306&, void*); + void *pData; + const int UID; + struct viewLink *next; +} ViewLink, *ViewLinkedList; + +char *addChar(char *pointer, const char character); + +char *dateTimeFormater(char *pointer, const uint8_t value, const char character); + +#endif //DEFINITION_H diff --git a/src/software_test/tcpServer_test/tcpServer_test.ino b/src/software_test/tcpServer_test/tcpServer_test.ino index 36eb800..8d6bd8c 100644 --- a/src/software_test/tcpServer_test/tcpServer_test.ino +++ b/src/software_test/tcpServer_test/tcpServer_test.ino @@ -15,6 +15,7 @@ uint16_t lastClientCount(0); //TCPServer server(80, MAX_CLIENT, 5); //WEBServer webServer(8080); +FTPServer ftpServer; WiFiEventHandler gotIpEventHandler, disconnectedEventHandler; @@ -53,6 +54,7 @@ void loop() { //server.runServer(); //webServer.runServer(); debugInfo(); + ftpServer.runServer(); }