Implementing FTP server
This commit is contained in:
parent
e77e879027
commit
31eb8eb589
@ -19,8 +19,8 @@ namespace DictionaryHelper
|
|||||||
{
|
{
|
||||||
if(string == NULL)
|
if(string == NULL)
|
||||||
{
|
{
|
||||||
_string = (char *) malloc((sizeof(char)) * 2); //+1 for the string terminating character
|
_string = (char *) malloc((sizeof(char)));
|
||||||
strcpy(_string, "");
|
_string[0] = '\0';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1 +1,58 @@
|
|||||||
#include "FTPClient.h"
|
#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<FTPClient>::FTPClientState::WAITING_FOR_COMMANDS),
|
||||||
|
_binaryFlag(FTPServer<FTPClient>::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,12 +2,31 @@
|
|||||||
#define FTPCLIENT_H
|
#define FTPCLIENT_H
|
||||||
|
|
||||||
#include "TCPClient.h"
|
#include "TCPClient.h"
|
||||||
|
#include "FTPServer.h"
|
||||||
|
#include "Dictionary.h"
|
||||||
|
|
||||||
class FTPClient
|
class FTPClient : public TCPClient
|
||||||
{
|
{
|
||||||
|
template<typename T>
|
||||||
|
friend class FTPServer;
|
||||||
public:
|
public:
|
||||||
|
FTPClient(WiFiClient client, uint8_t id, uint16_t clientCommandDataBufferSize = 255);
|
||||||
|
virtual ~FTPClient();
|
||||||
protected:
|
protected:
|
||||||
private:
|
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<DictionaryHelper::StringEntity> *_cmdParameters;
|
||||||
|
boolean _loggedIn;
|
||||||
|
char *_username;
|
||||||
|
|
||||||
|
FTPServer<FTPClient>::FTPClientState _ftpClientState;
|
||||||
|
FTPServer<FTPClient>::BinaryFlag _binaryFlag;
|
||||||
|
WiFiClient _dataClient; //data socket
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FTPCLIENT_H
|
#endif //FTPCLIENT_H
|
||||||
|
@ -2,20 +2,31 @@
|
|||||||
#define FTPSERVER_H
|
#define FTPSERVER_H
|
||||||
|
|
||||||
#include "TCPServer.h"
|
#include "TCPServer.h"
|
||||||
|
#define DEBUG_FTPS
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class FTPServer : public TCPServer<T>
|
class FTPServer : public TCPServer<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FTPServer(unsigned int port = 22, const char login = "", const char password = "", uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientCommandDataBufferSize), _login(NULL), _password(NULL)
|
enum FTPClientState {WAITING_FOR_COMMANDS};
|
||||||
{
|
enum BinaryFlag {OFF = 0, ON};
|
||||||
_login = (char *)malloc((sizeof(char) * strlen(login)) + 1);
|
|
||||||
if(_login != NULL)
|
|
||||||
strcpy(_login, login);
|
|
||||||
|
|
||||||
_password = (char *)malloc((sizeof(char) * strlen(password)) + 1);
|
FTPServer(unsigned int port = 21, const char *login = NULL, const char *password = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientCommandDataBufferSize),
|
||||||
if(_password != NULL)
|
_login(NULL),
|
||||||
|
_password(NULL),
|
||||||
|
_dataServer(1024)
|
||||||
|
{
|
||||||
|
if(login != NULL)
|
||||||
|
{
|
||||||
|
_login = (char *)malloc((sizeof(char) * strlen(login)) + 1);
|
||||||
|
strcpy(_login, login);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(password != NULL)
|
||||||
|
{
|
||||||
|
_password = (char *)malloc((sizeof(char) * strlen(password)) + 1);
|
||||||
strcpy(_password, password);
|
strcpy(_password, password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~FTPServer()
|
virtual ~FTPServer()
|
||||||
@ -24,9 +35,136 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual T* createNewClient(WiFiClient wc)
|
||||||
|
{
|
||||||
|
return new T(wc, TCPServer<T>::freeClientId(), TCPServer<T>::_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:
|
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 *_login;
|
||||||
char *_password;
|
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
|
#endif //FTPSERVER_H
|
||||||
|
33
src/software_test/tcpServer_test/StringEntity.cpp
Normal file
33
src/software_test/tcpServer_test/StringEntity.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "Dictionary.h"
|
||||||
|
#include "definition.h"
|
||||||
|
|
||||||
|
Dictionary<DictionaryHelper::StringEntity> *DictionaryHelper::StringEntity::split(char character)
|
||||||
|
{
|
||||||
|
Dictionary<DictionaryHelper::StringEntity> *ref = NULL;
|
||||||
|
unsigned int i(0), counter(0);
|
||||||
|
char *parseBuffer(NULL);
|
||||||
|
|
||||||
|
if(_string == NULL)return NULL;
|
||||||
|
|
||||||
|
ref = new Dictionary<StringEntity>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -36,7 +36,7 @@ class WEBServer : public TCPServer<T>
|
|||||||
uint16_t maxBodyBuffer;
|
uint16_t maxBodyBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
WEBServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 512) : TCPServer<T>(port, maxClient, clientDataBufferSize) {}
|
WEBServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientDataBufferSize) {}
|
||||||
|
|
||||||
boolean addApiRoutine(const char *uri, boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*), void *pData, HttpRequestMethod HRM = UNDEFINED)
|
boolean addApiRoutine(const char *uri, boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*), void *pData, HttpRequestMethod HRM = UNDEFINED)
|
||||||
{
|
{
|
||||||
@ -53,7 +53,7 @@ class WEBServer : public TCPServer<T>
|
|||||||
private:
|
private:
|
||||||
virtual T* createNewClient(WiFiClient wc)
|
virtual T* createNewClient(WiFiClient wc)
|
||||||
{
|
{
|
||||||
return new T(wc, TCPServer<T>::freeClientId());
|
return new T(wc, TCPServer<T>::freeClientId(), TCPServer<T>::_clientDataBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void greetClient(T *client)
|
virtual void greetClient(T *client)
|
||||||
|
51
src/software_test/tcpServer_test/definition.cpp
Normal file
51
src/software_test/tcpServer_test/definition.cpp
Normal file
@ -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;
|
||||||
|
}
|
60
src/software_test/tcpServer_test/definition.h
Normal file
60
src/software_test/tcpServer_test/definition.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef DEFINITION_H
|
||||||
|
#define DEFINITION_H
|
||||||
|
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
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
|
@ -15,6 +15,7 @@ uint16_t lastClientCount(0);
|
|||||||
|
|
||||||
//TCPServer<TCPClient> server(80, MAX_CLIENT, 5);
|
//TCPServer<TCPClient> server(80, MAX_CLIENT, 5);
|
||||||
//WEBServer<WEBClient> webServer(8080);
|
//WEBServer<WEBClient> webServer(8080);
|
||||||
|
FTPServer<FTPClient> ftpServer;
|
||||||
|
|
||||||
WiFiEventHandler gotIpEventHandler, disconnectedEventHandler;
|
WiFiEventHandler gotIpEventHandler, disconnectedEventHandler;
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ void loop() {
|
|||||||
//server.runServer();
|
//server.runServer();
|
||||||
//webServer.runServer();
|
//webServer.runServer();
|
||||||
debugInfo();
|
debugInfo();
|
||||||
|
ftpServer.runServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user